WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   General Authoring Discussion (https://www.wowinterface.com/forums/forumdisplay.php?f=20)
-   -   Rewriting Aurora, looking for feedback (https://www.wowinterface.com/forums/showthread.php?t=48687)

Haleth 12-17-13 01:38 PM

Rewriting Aurora, looking for feedback
 
Hello!

Over the years I've been updating and adding features to my addon, Aurora. It's gotten reasonably popular and many UI authors now include it in their UI, which I'm really happy about.

However, I started writing Aurora when I wasn't that experienced in programming, and a couple of glaring flaws in the addon's structure have become apparent over time as it got bigger and bigger and I learned more about programming. Namely:

- A lack of separation between core addon code, API, persistence, actual implementation, and appearance
- A lack of customizability, which is hard to implement because of the above issue
- The inability for UI authors to easily provide their own custom theme for Aurora to use, because of the two issues above

To address all of these problems, I've decided to rewrite Aurora from the ground up, focusing on good design principles and extensibility. I want the actual visual style to be completely independent from the implementation, so that I can add in-game options to allow people to customize colours, opacity, background and border style, etc. I also want UI authors to be able to provide their own custom style, without having to mess with Aurora's code each time I update the addon.

I've thought of several ways to do this, but I'm not entirely sure how to go about it. That's where I need help. I could:

- Provide a way for other authors to supply custom settings, such as colours and borders, in a certain format, and register them with Aurora (and request a theme reload to apply instantly). Aurora would then copy these settings to its own saved variables (if the theme wasn't saved already), letting users select the theme from an in-game option. They'd be able to modify the theme as well, or reset it to its defaults at any time (keep 2 cvar tables for each theme, the defaults and the current). All API functions (used both to restyle the Blizzard UI and in plugins for other addons) would then use these settings. The downside of this method is that it would be quite a bit of work to implement. It also means that even when disabling the addon that provided the theme, it would still be saved - so if the author of the other addon decides to modify their theme (or the theme changes dynamically), it would have to notify Aurora of this so that it can copy the new settings. Another problem is that some textures provided by the addon and saved in the cvars as a string might no longer be available if the addon is removed. I'd have to check for that, somehow.
- Instead of using settings like the above, I could code all necessary information about colours, borders, etc into the API functions itself. By default, they would provide the default "Aurora" style. I could then allow authors to register their custom API functions, and if those functions are found, Aurora would use them rather than the default ones. This seems a lot easier than the first method, but I'm not sure if it's actually possible. I'd have to ask each author to send me the name of their addon so that I can add it to Aurora's OptionalDeps, which seems less than ideal. Alternatively, I could provide a function for the addons to call to notify Aurora that a custom API is available. Aurora could then show a dialog prompting the user to reload the UI. Then, it would delay loading the API until the other addon has been loaded (using OnUpdate), but what if the user disabled the other addon in the meantime? Another consequence of this method is that custom styles could not be changed in Aurora itself, but only in the addon providing them. That could be seen as both a benefit and a drawback.
- I could do a mix of the above, letting other authors somehow override the default API, but still letting the default API use settings that are customizable in Aurora itself. Those settings could still only be used for the default theme, though - custom themes would have to be changed in the addon providing them.

There are probably more, and perhaps better methods to do this that I can't think of right now.

Apologies for the long post/text walls. Any ideas and suggestions would be much appreciated. :D

Nimhfree 12-17-13 05:00 PM

Not knowing how Aurora works internally and not actually terribly proficient in UI design myself, I will comment anyway. :-)

I would think if Aurora were working in a standalone mode it should be in control of how it changes the Blizzard UI. You might have only one theme or many depending on what you want to do. For your saved state, only save the theme that Aurora sets itself.

If Aurora is in slave mode (another addon is telling Aurora how to present a specific theme), I would imagine that master addon would have the optional dependency on Aurora, and the master would specify to Aurora the colors, textures, callbacks, etc. that are needed for Aurora to do its job. In this case Aurora should not save any specific settings as Aurora is not in control of the theme.

This should allow Aurora not to depend on any other addon, and let other master addons control how Aurora is used. If there is more than one master addon, that is not something Aurora needs to worry about since the user is in control of how the master addons are supposed to work. Let all hell break loose and let the master addon developers work it out.

Therefore, all you will need to do for multiple theme support is design your API to assume there will be multiple themes possible. All things that can be set by the theme should be overridable/definable/etc. You should be able to have any addon provide these theme configuration objects. In fact, Aurora should use its own API to do this itself. That is the perfect test of whether another addon will be able to use Aurora's themes properly because you use them yourself. Depending on how Aurora interacts with the Blizzard UI elements, you may be able to switch themes on the fly, or even have master addons do the same.

What gets interesting is if you allow users to override settings in a theme. Basically I am assuming a theme is a set of colors, textures, box widths, etc. If you do not allow the user to change the settings in a theme you only need to know what theme the user has selected in Aurora to put into your saved variables. Likewise, without letting the user to override values, you need not record any information from a theme from a master addon since Aurora is not in control of that. If, however, you allow the user to pick a theme, but then modify it a bit, you will want to record how the user's setting differ from the defaults for the theme. Then when the user reloads you can apply the default theme values modified by the user's specific choices. Now, in the case when Aurora is a slave addon to a master, the master should probably indicate to Aurora whether Aurora is allowed to override theme settings. If so, you need to decide whether the master should record the differences from the theme's defaults or whether Aurora needs to do this. My inclination is to let the master do this, which allows Aurora not to worry about anything concerning masters. If not, you would want to record the master addon's name with the modifications from defaults for the specified theme (assuming upon reload the master will once again pass in the theme and its defaults to Aurora).

For actual implementation I would make sure you keep the default information for a theme intact and separate from the actual values the user could change. This would allow you to easily reset back to default values for a theme. Depending on how much information you have associated with a theme you might just save the current theme values for when Aurora is in control vice saving differences from the default values.

You might want to consider being able to save multiple modified themes like profiles. You might want multiple toons to be able to access these profiles. If you do this, you might also think about being able to do so for themes that are provided by master addons, but this is where you find the biggest flaw because Aurora seems like it should know nothing about the master addon, and if it needed a callback from a master addon the profile you save from it would not be portable.

Sorry for the ranting...hopefully there is something in there that helps.

10leej 12-17-13 05:09 PM

I suggest a method for allowing authors to add their own textures for background and border. Or in my case have aurora make a frame for me to index then apply !Beautycase's border function.

Phanx 12-17-13 09:37 PM

I think Masque handles this situation pretty well.

Addons can register a skin with Masque by passing it a table describing the skin. For Masque, this table just contains strings and numbers describing the position and size of each texture, but for Aurora you would probably want functions, eg:

Code:

Aurora:RegisterSkin("MySkin", {
    SkinFrame = function(frame, settings)
          -- Aurora calls this to skin the specified frame. The plugin can just
          -- use SetBackdrop if that's all it wants to do, or it could add some
          -- texture objects, a background frame, etc.
    end,
    ApplySettings = function(frame, settings)
          -- Aurora calls this for each skinned frame when settings are
          -- changed. The plugin should do whatever is needed to apply
          -- the new settings.
    end,
    settings = {
          -- A table describing the settings the frame makes available.
          -- I'd model the format on AceOptions so you can easily
          -- construct the appropriate options GUI in Aurora.
          color = {
              type = "color",
              default = { r = 0.2, g = 0.2, b = 0.2 },
          },
          opacity = {
              type = "range", min = 0, max = 1, isPercent = true,
              default = 0.8,
          },
          showBackdrop = {
              type = "boolean",
              default = true,
          },
    },
})

The settings for each skin are saved by Aurora, eg:

Code:

Aurora.db = {
    profile = {
          ["Default"] = {
              selectedSkin = "MySkin",
              skinData = {
                    ["MySkin"] = {
                        color = { r = 0.5, g = 0, b = 0.5 },
                        opacity = 1,
                        showBackground = true,
                    },
                    ["OtherSkin"] = {
                        color1 = { r = 1, g = 1, b = 1 },
                        color2 = { r = 0, g = 0, b = 0 },
                        useGradient = false,
                    }
          }
    }
}

Then, whenever one of the skin's functions are called, it's passed (1) a reference to the frame it should do something with, and (b) a reference to the skin's saved settings table, eg:

Code:

settings = {
    color = { r = 0.5, g = 0, b = 0.5 },
    opacity = 1,
    showBackground = true,
}


10leej 12-17-13 11:38 PM

Forgot about masque, yeah something like that would be amazing.

Phanx 12-18-13 12:46 AM

Though, it has occurred to me now that this might not work as well if there are a lot of exceptions to the rule when skinning all the different frames, since every skin would need to write its own code for handling all the different frame types. I haven't actually looked at Aurora, though, so maybe it's pretty straightforward, like applying borders with !Beautycase.

Haleth 12-18-13 06:25 AM

Thanks for the feedback so far, it's been really useful.

There are indeed a lot of exceptions when it comes to skinning frames. I have a bunch of API functions to handle the most common widget templates, but often I need to manually code the rest myself. I do rely on settings for colours and borders, mind you, so other addons would just have to pass on those.

Part of the problem is reloading the entire theme if a new skin is found after Aurora already applied its own theme. It's doable, but very resource-intensive. I suppose I could ask the user to reload the UI the first time a new skin is registered and copied to the cvars, though, so the next time, Aurora can load it right away.

myrroddin 12-18-13 08:08 AM

To accommodate loading themes or skins after Aurora applies the default, couldn't you pull a page from LibSharedMedia-3.0 and fire a callback? That way no CPU or RAM is used unless specifically requested. I don't think you would need to set CVars; just add it to Aurora's SV file, which will be ignored if the theme or skin is disabled or not loaded.

zork 12-18-13 08:28 AM

This is what I used in oUF_Donut just to play around with templates:
Lua Code:
  1. --get the addon namespace
  2.   local addon, ns = ...
  3.  
  4.   --object container
  5.   local tmp = CreateFrame("Frame")
  6.   ns.tmp = tmp
  7.  
  8.   ---------------------------------------------
  9.   -- variables
  10.   ---------------------------------------------
  11.  
  12.   tmp.styles = {}
  13.  
  14.   ---------------------------------------------
  15.   -- template functions
  16.   ---------------------------------------------
  17.  
  18.   --template RegisterTemplateByName
  19.   function tmp:RegisterTemplateByName(name,data)
  20.     tmp.styles[name] = data
  21.   end
  22.  
  23.   --template UnregisterTemplateByName
  24.   function tmp:UnregisterTemplateByName(name)
  25.     tmp.styles[name] = nil
  26.   end
  27.  
  28.   --template GetTemplateByName
  29.   function tmp:GetTemplateByName(name)
  30.     return tmp.styles[name]
  31.   end

If you make your templating object global any addon could use them.

Another way is adding new templating or skinning functions to specific frame meta tables. !BeautyCase does this for example. That way you add functions to the default wow api via progressive enhancement. http://code.google.com/p/rothui/sour...ore/lib.lua#84
Lua Code:
  1. local frame = FRAME_BY_GLOBALNAME or CreateFrame("Frame")
  2. local mt = getmetatable(frame).__index
  3. mt.SkinFrame = function(self,name,data)
  4.   --do stuff
  5. end
  6. frame:SkinFrame("name", {})

I'm in no way an expert on that topic but it got the job done for what I needed.

10leej 12-18-13 09:00 AM

Quote:

Originally Posted by Haleth (Post 288497)
I suppose I could ask the user to reload the UI the first time a new skin is registered and copied to the cvars, though, so the next time, Aurora can load it right away.

That would be the best way to do it. Causing someone to reload their UI isn't all that bad their probably not doing anything else when their messing with aurora skins anyway.

zork 12-18-13 09:29 AM

You could prevent the reload if by using a redraw function that updates all your adjusted objects. Basically you need a specific function set that allows updating of frame textures/colors only.

If you need to create new frames that would be bad because you cannot delete old frames, only re-use them.

Haleth 12-18-13 11:03 AM

A redraw function would be doable as well, if it only has to happen the first time. Afterwards it can be loaded from saved vars.

How would I let other addons override the default API, though? Functions can't be stored in saved variables to my knowledge. Using callbacks isn't exactly viable either. Load times would be too long if Aurora applies its default skin and then gets asked to reload the entire skin again. A solution might be to put the default skin in a separate addon, which the user can disable and replace by another skin addon - but that would remove the possibility of changing skin on the fly.

10leej 12-18-13 11:52 AM

Could just be as simple as just letting players replace textures.

Tonyleila 12-18-13 08:46 PM

I remember there was a time where you were about to abandon Aurora - always thinking of this I'm pretty happy with the fast and good updates you provided since then.

About colours and borders - that woud be interesting I was thinking about using a light gray version of Aurora with black font color everywhere and a orange highlight color fonts for Sword Art Online UI . All I coud do in the lua without changing too much was something like this http://i.imgur.com/wjcl8xX.jpg... since Aurora only reskinns the fonts that are not already in the right color.

Woud be realy cool if we coud change the yellow color of blizzards font to something else like blue :D

Also I'm not shure if this helps but before I used Aurora I tested "Skinner" and as far as I remember it has the options you want to add and even reskinns Addons. BUT I don't want aurora to become Skinner 2.0 its just too much! When I look at all the options I don't want to use this addon :(


All times are GMT -6. The time now is 05:21 PM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI