deployment
This commit is contained in:
13
src/utils/__init__.py
Normal file
13
src/utils/__init__.py
Normal file
@@ -0,0 +1,13 @@
|
||||
"""
|
||||
Utility modules for the Text Texture Generator addon.
|
||||
"""
|
||||
|
||||
from .constants import bl_info
|
||||
from .system import install_pillow, get_system_fonts, get_font_enum_items
|
||||
|
||||
__all__ = [
|
||||
'bl_info',
|
||||
'install_pillow',
|
||||
'get_system_fonts',
|
||||
'get_font_enum_items'
|
||||
]
|
||||
BIN
src/utils/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
src/utils/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
src/utils/__pycache__/constants.cpython-311.pyc
Normal file
BIN
src/utils/__pycache__/constants.cpython-311.pyc
Normal file
Binary file not shown.
BIN
src/utils/__pycache__/feature_flags.cpython-311.pyc
Normal file
BIN
src/utils/__pycache__/feature_flags.cpython-311.pyc
Normal file
Binary file not shown.
BIN
src/utils/__pycache__/system.cpython-311.pyc
Normal file
BIN
src/utils/__pycache__/system.cpython-311.pyc
Normal file
Binary file not shown.
32
src/utils/constants.py
Normal file
32
src/utils/constants.py
Normal file
@@ -0,0 +1,32 @@
|
||||
"""
|
||||
Constants and metadata for the Text Texture Generator addon.
|
||||
"""
|
||||
|
||||
bl_info = {
|
||||
"name": "Text Texture Generator",
|
||||
"author": "Marc Mintel <marc@mintel.me>",
|
||||
"version": (1, 0, 0),
|
||||
"blender": (4, 0, 0),
|
||||
"location": "3D View > Sidebar (N) > Tool Tab | Shader Editor > Sidebar > Tool Tab",
|
||||
"description": "Generate image textures from text with accurate dimensions and instant live preview",
|
||||
"category": "Material",
|
||||
}
|
||||
|
||||
# Version information
|
||||
VERSION_TYPE = "full" # "free" or "full"
|
||||
|
||||
# Version-specific limits (applied at build time through file exclusions)
|
||||
def get_version_limits():
|
||||
"""Get version-specific limits."""
|
||||
return {
|
||||
"max_texture_size": 4096,
|
||||
"max_concurrent_operations": 4
|
||||
}
|
||||
|
||||
def is_free_version():
|
||||
"""Check if this is the free version."""
|
||||
return VERSION_TYPE == "free"
|
||||
|
||||
def is_full_version():
|
||||
"""Check if this is the full version."""
|
||||
return VERSION_TYPE == "full"
|
||||
150
src/utils/feature_flags.py.backup
Normal file
150
src/utils/feature_flags.py.backup
Normal file
@@ -0,0 +1,150 @@
|
||||
"""
|
||||
Feature flag system for Text Texture Generator.
|
||||
Provides runtime checking of enabled features based on build configuration.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Any, Optional
|
||||
|
||||
# Import the build-time injected constants
|
||||
try:
|
||||
from .constants import ENABLED_FEATURES, VERSION_TYPE, get_version_limits
|
||||
except ImportError:
|
||||
# Fallback for development/testing
|
||||
ENABLED_FEATURES = ["basic", "preview", "advanced_styling", "normal_maps", "presets"]
|
||||
VERSION_TYPE = "full"
|
||||
def get_version_limits():
|
||||
return {"max_texture_size": 4096, "max_concurrent_operations": 4}
|
||||
|
||||
class FeatureManager:
|
||||
"""Manages feature flags and version-specific limitations."""
|
||||
|
||||
def __init__(self):
|
||||
self._enabled_features = set(ENABLED_FEATURES)
|
||||
self._version_type = VERSION_TYPE
|
||||
self._limits = get_version_limits()
|
||||
self._features_config = self._load_features_config()
|
||||
|
||||
def _load_features_config(self) -> Optional[Dict]:
|
||||
"""Load the features configuration file if available."""
|
||||
try:
|
||||
# Try to load from build directory (development)
|
||||
config_path = Path(__file__).parent.parent.parent / "build" / "features.json"
|
||||
if config_path.exists():
|
||||
with open(config_path, 'r') as f:
|
||||
return json.load(f)
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
|
||||
def is_feature_enabled(self, feature_name: str) -> bool:
|
||||
"""Check if a feature is enabled in the current build."""
|
||||
return feature_name in self._enabled_features
|
||||
|
||||
def get_enabled_features(self) -> List[str]:
|
||||
"""Get list of all enabled features."""
|
||||
return list(self._enabled_features)
|
||||
|
||||
def get_version_type(self) -> str:
|
||||
"""Get the version type (free or full)."""
|
||||
return self._version_type
|
||||
|
||||
def get_limit(self, limit_name: str, default: Any = None) -> Any:
|
||||
"""Get a version-specific limit."""
|
||||
return self._limits.get(limit_name, default)
|
||||
|
||||
def get_max_texture_size(self) -> int:
|
||||
"""Get the maximum texture size for this version."""
|
||||
return self.get_limit("max_texture_size", 1024)
|
||||
|
||||
def get_max_concurrent_operations(self) -> int:
|
||||
"""Get the maximum concurrent operations for this version."""
|
||||
return self.get_limit("max_concurrent_operations", 1)
|
||||
|
||||
def require_feature(self, feature_name: str) -> bool:
|
||||
"""Check if feature is enabled, raise exception if not."""
|
||||
if not self.is_feature_enabled(feature_name):
|
||||
raise FeatureNotAvailableError(
|
||||
f"Feature '{feature_name}' is not available in {self._version_type} version"
|
||||
)
|
||||
return True
|
||||
|
||||
def get_feature_info(self, feature_name: str) -> Optional[Dict]:
|
||||
"""Get detailed information about a feature."""
|
||||
if not self._features_config:
|
||||
return None
|
||||
|
||||
return self._features_config.get("features", {}).get(feature_name)
|
||||
|
||||
def is_component_enabled(self, component_path: str) -> bool:
|
||||
"""Check if a specific component is enabled based on feature flags."""
|
||||
if not self._features_config:
|
||||
return True # Assume enabled if no config
|
||||
|
||||
features = self._features_config.get("features", {})
|
||||
for feature_name, feature_config in features.items():
|
||||
if self.is_feature_enabled(feature_name):
|
||||
components = feature_config.get("components", [])
|
||||
if component_path in components:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
class FeatureNotAvailableError(Exception):
|
||||
"""Raised when trying to use a feature that's not available in the current version."""
|
||||
pass
|
||||
|
||||
# Global feature manager instance
|
||||
feature_manager = FeatureManager()
|
||||
|
||||
# Convenience functions
|
||||
def is_feature_enabled(feature_name: str) -> bool:
|
||||
"""Check if a feature is enabled."""
|
||||
return feature_manager.is_feature_enabled(feature_name)
|
||||
|
||||
def require_feature(feature_name: str) -> bool:
|
||||
"""Require a feature to be enabled."""
|
||||
return feature_manager.require_feature(feature_name)
|
||||
|
||||
def get_version_type() -> str:
|
||||
"""Get the current version type."""
|
||||
return feature_manager.get_version_type()
|
||||
|
||||
def get_max_texture_size() -> int:
|
||||
"""Get maximum texture size for this version."""
|
||||
return feature_manager.get_max_texture_size()
|
||||
|
||||
def get_max_concurrent_operations() -> int:
|
||||
"""Get maximum concurrent operations for this version."""
|
||||
return feature_manager.get_max_concurrent_operations()
|
||||
|
||||
# Decorators for feature-gated functionality
|
||||
def feature_required(feature_name: str):
|
||||
"""Decorator to require a feature for a function or method."""
|
||||
def decorator(func):
|
||||
def wrapper(*args, **kwargs):
|
||||
require_feature(feature_name)
|
||||
return func(*args, **kwargs)
|
||||
wrapper.__name__ = func.__name__
|
||||
wrapper.__doc__ = func.__doc__
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
def feature_gated(feature_name: str, fallback=None):
|
||||
"""Decorator to conditionally execute a function based on feature availability."""
|
||||
def decorator(func):
|
||||
def wrapper(*args, **kwargs):
|
||||
if is_feature_enabled(feature_name):
|
||||
return func(*args, **kwargs)
|
||||
elif fallback is not None:
|
||||
return fallback(*args, **kwargs) if callable(fallback) else fallback
|
||||
else:
|
||||
raise FeatureNotAvailableError(
|
||||
f"Feature '{feature_name}' is not available in {get_version_type()} version"
|
||||
)
|
||||
wrapper.__name__ = func.__name__
|
||||
wrapper.__doc__ = func.__doc__
|
||||
return wrapper
|
||||
return decorator
|
||||
84
src/utils/system.py
Normal file
84
src/utils/system.py
Normal file
@@ -0,0 +1,84 @@
|
||||
"""
|
||||
System utility functions for the Text Texture Generator addon.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import platform
|
||||
import os
|
||||
|
||||
def install_pillow():
|
||||
"""Install Pillow if not available"""
|
||||
try:
|
||||
import PIL
|
||||
except ImportError:
|
||||
print("Installing Pillow...")
|
||||
subprocess.check_call([sys.executable, "-m", "pip", "install", "pillow>=10.0.0"])
|
||||
|
||||
def get_system_fonts():
|
||||
"""Get detailed list of available system fonts with paths"""
|
||||
try:
|
||||
from PIL import ImageFont
|
||||
import glob
|
||||
|
||||
fonts = {}
|
||||
system = platform.system()
|
||||
|
||||
if system == "Windows":
|
||||
font_dirs = [
|
||||
"C:/Windows/Fonts/",
|
||||
os.path.expanduser("~/AppData/Local/Microsoft/Windows/Fonts/")
|
||||
]
|
||||
extensions = ["*.ttf", "*.ttc", "*.otf"]
|
||||
elif system == "Darwin": # macOS
|
||||
font_dirs = [
|
||||
"/System/Library/Fonts/",
|
||||
"/Library/Fonts/",
|
||||
os.path.expanduser("~/Library/Fonts/")
|
||||
]
|
||||
extensions = ["*.ttf", "*.ttc", "*.otf", "*.dfont"]
|
||||
else: # Linux
|
||||
font_dirs = [
|
||||
"/usr/share/fonts/",
|
||||
"/usr/local/share/fonts/",
|
||||
os.path.expanduser("~/.local/share/fonts/"),
|
||||
os.path.expanduser("~/.fonts/")
|
||||
]
|
||||
extensions = ["*.ttf", "*.ttc", "*.otf"]
|
||||
|
||||
for font_dir in font_dirs:
|
||||
if os.path.exists(font_dir):
|
||||
for ext in extensions:
|
||||
for font_path in glob.glob(os.path.join(font_dir, "**", ext), recursive=True):
|
||||
try:
|
||||
font_name = os.path.splitext(os.path.basename(font_path))[0]
|
||||
font_name = font_name.replace("-", " ").replace("_", " ")
|
||||
fonts[font_name] = font_path
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
return fonts
|
||||
except ImportError:
|
||||
return {}
|
||||
|
||||
def get_font_enum_items(self, context):
|
||||
"""Dynamic enum items for font selection"""
|
||||
items = [("default", "Default Font", "Use system default font", 0)]
|
||||
|
||||
if not hasattr(get_font_enum_items, 'cached_fonts'):
|
||||
get_font_enum_items.cached_fonts = get_system_fonts()
|
||||
|
||||
fonts = get_font_enum_items.cached_fonts
|
||||
|
||||
for i, (font_name, font_path) in enumerate(sorted(fonts.items())[:50]):
|
||||
items.append((font_path, font_name, f"Font: {font_name}", i + 1))
|
||||
|
||||
return items
|
||||
|
||||
def get_anchor_point_matrix():
|
||||
"""Return a 3x3 matrix of anchor point identifiers for UI positioning grid"""
|
||||
return [
|
||||
['TOP_LEFT', 'TOP_CENTER', 'TOP_RIGHT'],
|
||||
['MIDDLE_LEFT', 'MIDDLE_CENTER', 'MIDDLE_RIGHT'],
|
||||
['BOTTOM_LEFT', 'BOTTOM_CENTER', 'BOTTOM_RIGHT']
|
||||
]
|
||||
Reference in New Issue
Block a user