Latest News
11/15
I republished my first Tweaker tutorial for the new site: http://www.tweakeraddon.com/tuts/modifying-the-viewport
There are some other tutorials listed in the menu, but they're not created yet. All the tut and doc stuff is still static at this point and it takes awhile to create.
11/1
Looking back at how big Tweaker grew with version 1.2, it struck me that some documentation is going to be handy. I certainly don't expect people to read through all the code in order to see what's available, but that's about all that you can do at the moment. Well, that, and using /dump can give a rundown of what's available -- /dump TweakerColorizer, for instance, will show all the properties and methods and what-not of that class.
But that's still a pain, so I'm working on the documentation. It's not polished yet, but the data for TweakerColorizer is up. Let me know what ya think.
http://tweakeraddon.appspot.com/docs/TweakerColorizer
I'm also in the process of getting http://www.tweakeraddon.com to work but these DNS and CNAME things can take up to 2 days to propagate.
Update
I had some fun with MooTools and made the menus on the doc page move up and down with the page, and I'm loving the results. If your browser window is too small to fit the entire menu, it gets really smart and only moves as needed, to either the top or bottom edge depending on the direction you scrolled.
I also said 50 Hail Marys and opened up IE to see how the page would look. I swear, that browser is the worst thing to happen to the web. I managed to get the menus moving just fine in IE8, but the code highlighting... well, it's not pretty. Apparently, IE normalizes their stored HTML, not just what's rendered, so when Javascript tries to access it, it gets the normalized version. This means when my script goes to parse the code, white space is all reduced to a single space character. That means not only can I not display line breaks and tabs, but I can't even detect them in order to know, say, when a comment ends.
Thank you, Microsoft, for saving me those precious bytes of memory.
Get a real browser
(Is it ironic that my IE just froze up?)
10/29
Tweaker 1.2 is being released today. It's been stable for quite some time for myself now, and the other features that are pending for Tweaker can wait for another version. My time has been scarce lately and it's already been far too long of a wait. The website will hopefully be more of a focus now as I try to get it going so that Tweaker can be better documented. In the meantime, feel free to browse the source code or use the /dump command to see what functionality is available.
/dump Tweaker
/dump TweakerColorizer
/dump TweakerLogger
/dump TweakerSlash
TWEAKER 1.2 CHANGELOG
File Structure
- Users will no longer be confined to creating their tweaks in config.lua. Tweaks can be made and registered to Tweaker at any time. As such, common tweaks will be able to be packaged and distributed. You may also want to consider making a MyTweaks addon for your custom tweaks. This change will add overhead, but I'll keep it as minimal as possible.
- config.lua will be loaded after Tweaker, so people using config.lua can make use of the Tweaker Global API (which will be more important now than before)
Development Tools
Coloring
- It's a common task, why not have a tool for it? I've found myself using it throughout various modules.
- TweakerColorizer:new() to instantiate, new() takes an optional table of name/color pairs, where name is any string and color is a series of 6 hexadecimal digits following standard notation, rrggbb, such that ffffff is white and 000000 is black. (I should probably update this in the future to take 6 or 8 digits so alpha can optionally be included.)
- Colorizers can be instantiated from other colorizers, and thus inherit their colors. So if a = TweakerColorizer:new() and a defines a color, burple, and b is a new colorizer created from a, such that b = a:new(), then b will also have access to burple and any other colors that a has, regardless of them being added before or after b's instantiation. You may also redefine colors on b to have them take precedence. You'll find that I frequently name colors in my modules according to functionality, so the Logger module has a color named trace that's used for trace messages. Anything inheriting from my logger module will also have a trace color that can then be set to whatever color the person wants to use for his/her trace messages.
- :Apply(color, string, ...) takes a color, by name, and applies it to the string. If additional arguments are included, string is assumed to be a formatstring, and string.format(formstring, ...) is called. If color is not the name of a defined color, it's treated as the color itself. The resultant string is returned.
- :RegexApply(color, regex, string, ...) Here, a regex pattern is also included. Any characters matching the pattern will have the color applied to them in the returned string result.
- Many more, check the files or /dump TweakerColorizer
Logging
- Enhanced logging features. I've borrowed the logging style used in the log4j java module to implement levels of logging. Tweaks will be able to define their own level of logging separate from the global default so users can get details on a particular tweak that they're working on and not every tweak in their repertoire.
- Tweaker itself will have more log messages than before, and users will be able to use Tweaker to generate logging messages for their tweaks.
- Log messages can be throttled. A global setting will be available to determine how often the same log message can be repeated, and disabling the setting will disable the throttling. (I'm not too sure about keeping this. Since trace messages can be somewhat generic and inferred by their context, the throttling can remove some that you expect to see when debugging.) Removed
- TweakerLogger is a new class that can be instantiated via TweakerLogger:new(). Users may use Tweaker's log via Tweaker.log or instantiate their own if need be.
Slash Command Handling
- TweakerSlashCommand:new() and TweakerSlashCommandHandler:new() to create a command and a handler, respectively.
- SlashCommand objects should have the following properties: commands (array of strings, such as "apples" or "oranges", to follow the base slash command), help (the help text to include when using the help command, briefly explaining what the command does, such as "gives the requested number of apples, defaults to 1"), args (the args that can be included after the command, such as "[<any digit>]" to say that any digit may optionally be included), call (the function to call when the command is requested by the user in order to process any arguments)
- call currently supports only one arguments, text, and it's up to the call function to interpret and parse the text, or throw an error.
- SlashCommandHandler objects should be defined with two properties: Name and Commands (notice the capitalization here). Name is how the handler will identify itself to the end user. For instance, "Tweaker." Commands is an array of slash commands, such as { "/tweaker", "/tweak" }
- All new SlashCommandHandler objects have a default help command, which can be called simply via /slash help or for detailed info via /slash help command.
/dump command
- Enhanced /dump command (can be turned off). I love that WoW finally includes its own /dump command, but I think it's ugly. I've created one similar to what AceConsole offers, but it's currently using 300-350 lines of code instead of the 2500-3000 lines that Ace uses.
The Tweaker Process
- Tweaks are no longer created at PLAYER_LOGIN. They are put into a queue and created as soon as all of their requirements are met: ie. Parent widget must exist, Template tweaks must have been processed, and Requirements widgets must all exist.
- Tweaker_Data has been removed. Use Tweaker.RegisterTweak({}) and Tweaker.RegisterTweaks({{}, {}, {}})
Tweak Attributes
Widget Names
- Tweaks will no longer be given a default name if one is not supplied, the resulting widget will just be unnamed and users will not be able to reference it. With the new structure, there is no simple top-to-bottom order of tweaks, so there's no way of consistently naming them. I might as well not bother naming them at all.
- Names are no longer assumed to be alphanumeric. The Widget API allows any character, so I figure I need to as well. I will not support tweaks with duplicate names though.
- Many properties are being redone for various reasons, although many are because of the change in names. The current shorthand will still be available (hopefully, maybe, for some things) for tweaks/widgets that don't use spaces in their name though, and I advise everyone to abide by the standard alphanumeric pattern for naming things.
Templating
- Template has been renamed to Templates (with an s) since, like Points, Textures, FontStrings, etc, it's designed to take a table. In this case, each item in the table should be the name of a tweak to inherit attributes from. Like with Points, the shorthand Templates = "BaseTweak" does work if there's only one tweak to inherit from (and it's likely less memory use).
- InheritsFrom has been added, and only applies to tweaks that are creating new objects. It specifies what standard WoW widget should be inherited from: CreateFrame(Type, Name, Parent, InheritsFrom)
Requirements
- Requirements has been added and works like Templates and Points in that it can be a table of string values or just a string if there's one value. Requirements are those widgets that must exist before the tweak can be processed. If you're creating a tweak for a widget that may not exist yet, you can specify as much with: { Name = "DelayedWidget", Requirements = "DelayedWidget" } -- the tweak won't be processed until the widget exists, at which point the tweak will apply itself to that widget instead of creating a new one.
Scripts/Functions
- OnLoad is no longer called as soon as a tweak is processed. Instead, Startup is a new supported attribute of tweaks, and defines a function to call at this same point in time.
Timers
- Timers is a new attribute, and defines a list of timers. The advantage here is that there's a single function handling timer execution, the user doesn't need to track elapsed time manually every place that a periodic event is needed.
Code:
Timers = {
{
Name = <string>,
Interval = <number>,
Function = <function (self, elapsed)>
},
{
Name = <string>,
...
},
...
}
Name is optional and currently doesn't have a use. Interval defaults to 0, which means to repeat as often as possible. Function is called whenever the elapsed time meets or exceeds the Interval and then elapsed time is reset.
Custom Attributes
- Custom attributes can no longer be defined in the main area of the Tweak. Instead, the CustomAttributes attribute has been defined and can hold any custom data that needs to be propagated to the widget.
Code:
{
Name = "MyTweak",
CustomAttributes = {
myBool = true,
myInt = 2,
myFunc = function() end,
...
},
...
}
The resulting widget will have the CustomAttributes accessible at its base level, MyTweak.myBool, MyTweak.myInt, myTweak.myFunc, etc.
DESCRIPTION
Tweaker is the public start of an experiment in addon design. I love having options, but giving options to addons is a complicated process. Libraries have been written to simplify things for addon authors, but the mechanics behind them are still rather involved. I currently have over 200 folders in my AddOns directory. I have over 30 megs of SavedVariable files for my main toon. I need a change, and I imagine others do as well (for more of my thoughts on this, please visit my blog post entitled
New Addon Design).
When it comes to the appearance of something, I want as many options available to me as the WoW Widget API will allow. Obviously, it's not practical to include that many settings in any addon. I started to use panel addons to give myself some flexibility. I couldn't modify existing things, but I could create panels, and they looked neat.
Tweaker started off that way. Like other panel addons, it could create panels of varying sizes and colors. Images and text could be added. Unlike many though, multiple images and text strings could be added to a single panel. Everything could be positioned not with just a single anchor, but with many anchors. It grew to the point that the entire widget API was exposed. I was only using half as much memory as my previous panel addon, but I still wanted more out of it.
So I added event handling. It was simple to do, and simpler to use. With panels being able to respond to events, they could change dynamically. I had been using a LDB display plugin along with a data plugin to display my current zone somewhere other than over the minimap. I decided to use Tweaker to create a frame for it instead. My own code ended up with a much smaller memory footprint (virtually none) and it was able to change the color of the text based on if the area was friendly, hostile, neutral, or whatever just like the tooltip for the minimap's zone panel. I also have it designed to show both the primary and sub zone names. Well, there's one addon I can get rid of now.
I moved on to create one for showing my coordinates. Got rid of an old addon for that. Another for the current time. And dropped another addon.
I then figured I could create buttons just as easily as panels, so I made a button for my calendar, and an icon for my mail. I also wanted a way to easily see if I was at the defense minimum and if I was hit or expertise capped, so I created a panel for that info too.
All these things are currently in my screenshot on the right. The arrow is from TomTom, and it fits quite nicely where it is. I plan to add more later.
None of these things were difficult to do, but this addon isn't for everyone either. It's not user friendly. It will take me time to write up appropriate documentation. I also intend on writing a number of tutorials for the things I've mentioned above, and more. But if you're like me and you like to tweak things, give Tweaker a try. Leave comments with any questions or suggestions you have, and I'll try to get some documentation and tutorials out as quickly as I can.
Some important notes for the time being:
- If you supply the name of an existing UI element, tweaker will operate on that element instead of creating a new one.
- If you declare an element with Virtual = true listed in its properties, it will not be created in the game but will instead remain "virtual" (this is handy for inheritance)
- For any element, you can create a Templates property. This property takes an array of elements (by name) to inherit from. Example: Templates = { "BasePanel", "TextPanel" } will inherit the properties of BasePanel and then those of TextPanel. Only properties that aren't defined in the inheriting tweak are inherited.
- There's not much error checking. That adds overhead that I'd prefer to avoid. If you do mess things up, a simple reloadui should fix them. There is some logging by calling Tweaker:SetGlobalLogLevel(level) where level can be "trace", "debug", "info", "warn", "error", or "fatal" -- all higher levels are also logged and tweak-specific levels can be declared by setting the LogLevel property of a tweak to one of the above levels as well.
DIRECTIONS
- Download and extract to Interface\Addons like normal
- In the Tweaker folder, create a file named config.lua
- In config.lua, call Tweaker:RegisterTweaks with an array of tables
- Populate the tables in a manner similar to the example below
EXAMPLE config.lua
Code:
Tweaker:RegisterTweaks({
{
Name = "SamplePanel",
Parent = "UIParent",
FrameStrata = "BACKGROUND",
FrameLevel = 2,
Points = {
"CENTER",
},
Width = 200,
Height = 50,
Textures = {
{
Name = "$parentBorder",
DrawLayer = "BACKGROUND",
Texture = "0.12 0.12 0.12",
Points = {
"TOPLEFT -3 3",
"BOTTOMRIGHT 3 -3",
},
},
{
Name = "$parentBackground",
DrawLayer = "BORDER",
Texture = "0.05 0.05 0.05",
Points = "ALL",
},
},
FontStrings = {
{
Name = "$parentText",
Font = "Fonts\FRIZQT__.TTF 12 OUTLINE",
JustifyH = "CENTER",
JustifyV = "MIDDLE",
Points = "ALL",
Text = "Sample",
},
},
},
})