haxeui/haxeui-core

View on GitHub
haxe/ui/themes/ThemeManager.hx

Summary

Maintainability
Test Coverage
package haxe.ui.themes;

import haxe.ds.ArraySort;
import haxe.ui.Toolkit;
import haxe.ui.events.ThemeEvent;
import haxe.ui.util.EventMap;

class ThemeManager {
    private static var _instance:ThemeManager;
    public static var instance(get, null):ThemeManager;
    private static function get_instance():ThemeManager {
        if (_instance == null) {
            _instance = new ThemeManager();
        }
        return _instance;
    }

    //****************************************************************************************************
    // Instance
    //****************************************************************************************************
    private var _themes:Map<String, Theme>;
    private var _themeImages:Map<String, ThemeImageEntry>;
    private var _eventMap:EventMap = null;

    public function new() {
        _themes = new Map<String, Theme>();
    }

    public function registerEvent<T:ThemeEvent>(type:String, listener:T->Void, priority:Int = 0) {
        if (_eventMap == null) {
            _eventMap = new EventMap();
        }
        
        _eventMap.add(type, listener);
    }
    
    public function unregisterEvent<T:ThemeEvent>(type:String, listener:T->Void) {
        if (_eventMap == null) {
            return;
        }
        
        _eventMap.remove(type, listener);
    }
    
    private function dispatch(event:ThemeEvent) {
        if (_eventMap == null) {
            return;
        }
        
        _eventMap.invoke(event.type, new ThemeEvent(ThemeEvent.THEME_CHANGED));
    }
    
    public function getTheme(themeName:String):Theme {
        var theme:Theme = findTheme(themeName);
        if (theme == null) {
            theme = new Theme();
            _themes.set(themeName, theme);
        }
        return theme;
    }

    public function findTheme(themeName:String):Theme {
        var t = null;
        for (name in _themes.keys()) {
            if (name.toLowerCase() == themeName.toLowerCase()) {
                t = _themes.get(name);
                break;
            }
        }
        return t;
    }

    public function addStyleResource(themeName:String, resourceId:String, priority:Float = 0, styleData:String = null) {
        getTheme(themeName).styles.push({
            resourceId: resourceId,
            priority: priority,
            styleData: styleData
        });
    }

    public function setThemeVar(themeName:String, varName:String, varValue:String) {
        var theme = getTheme(themeName);
        if (theme == null) {
            return;
        }
        theme.vars.set(varName, varValue);
    }
    
    public function setCurrentThemeVar(varName:String, varValue:String) {
        setThemeVar(Toolkit.theme, varName, varValue);
    }
    
    public function addImageResource(themeName:String, id:String, resourceId:String, priority:Float = 0) {
        getTheme(themeName).images.push({
            id: id,
            resourceId: resourceId,
            priority: priority
        });
    }

    private var currentThemeVars:Map<String, String> = new Map<String, String>();
    
    public function applyTheme(themeName:String) {
        if (findTheme(themeName) == null) {
            trace("WARNING: theme '" + themeName + "' not found, falling back to default theme");
            themeName = "default";
        }
        Toolkit.styleSheet.clear("default");

        // vars
        var finalVars:Map<String, String> = new Map<String, String>();
        buildThemeVars("global", finalVars);
        buildThemeVars(themeName, finalVars);
        currentThemeVars = new Map<String, String>();
        for (k in finalVars.keys()) {
            currentThemeVars.set(k, finalVars.get(k));
        }

        
        // stylesheet entries
        var entries:Array<ThemeEntry> = [];
        buildThemeEntries("global", entries);
        buildThemeEntries(themeName, entries);

        ArraySort.sort(entries, function(a, b):Int {
            if (a.priority < b.priority) return -1;
            else if (a.priority > b.priority) return 1;
            return 0;
        });

        for (e in entries) {
            applyResource(e.resourceId, e.styleData);
        }

        // images
        var images:Array<ThemeImageEntry> = [];
        buildThemeImages("global", images);
        buildThemeImages(themeName, images);
        ArraySort.sort(images, function(a, b):Int {
            if (a.priority < b.priority) return -1;
            else if (a.priority > b.priority) return 1;
            return 0;
        });

        for (i in images) {
            if (_themeImages == null) {
                _themeImages = new Map<String, ThemeImageEntry>();
            }
            _themeImages.set(i.id, i);
        }
        
        dispatch(new ThemeEvent(ThemeEvent.THEME_CHANGED));
    }

    public function applyResource(resourceId:String, styleData:String = null) {
        var style:String = "";
        if (resourceId != null) {
            style = Toolkit.assets.getText(resourceId);
        }
        if (styleData != null) {
            if (style == null) {
                style = "";
            }
            style += "\n" + styleData;
        }
        if (style != null) {
            addStyleString(style);
        } else {
            #if debug
            trace("WARNING: could not find " + resourceId);
            #end
        }
    }

    public function addStyleString(style:String) {
        Toolkit.styleSheet.parse(style);
    }

    private function buildThemeVars(themeName:String, vars:Map<String, String>) {
        var theme:Theme = findTheme(themeName);
        if (theme == null) {
            return;
        }
        if (theme.parent != null) {
            buildThemeVars(theme.parent, vars);
        }
        
        for (k in theme.vars.keys()) {
            var v = theme.vars.get(k);
            vars.set(k, v);
        }
    }
    
    private function buildThemeEntries(themeName:String, arr:Array<ThemeEntry>) {
        var theme:Theme = findTheme(themeName);
        if (theme == null) {
            return;
        }
        if (theme.parent != null) {
            buildThemeEntries(theme.parent, arr);
        }

        for (s in theme.styles) {
            arr.push(s);
        }
    }

    private function buildThemeImages(themeName:String, arr:Array<ThemeImageEntry>) {
        var theme:Theme = findTheme(themeName);
        if (theme == null) {
            return;
        }
        if (theme.parent != null) {
            buildThemeImages(theme.parent, arr);
        }

        for (s in theme.images) {
            arr.push(s);
        }
    }

    //****************************************************************************************************
    // Helpers
    //****************************************************************************************************
    public function image(id:String):String {
        var image = _themeImages.get(id);
        if (image == null) {
            return null;
        }
        return image.resourceId;
    }

    public function icon(id:String):String { // semantics
        return image(id);
    }
}