Compare commits
2 Commits
7e69b12f71
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| a4cc026e38 | |||
| 65843c255a |
@@ -5,7 +5,7 @@
|
|||||||
set -e # Exit on any error
|
set -e # Exit on any error
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
PROJECT_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")"
|
||||||
|
|
||||||
echo "=== Signage Player Offline Installation ==="
|
echo "=== Signage Player Offline Installation ==="
|
||||||
echo "Project root: $PROJECT_ROOT"
|
echo "Project root: $PROJECT_ROOT"
|
||||||
@@ -45,10 +45,13 @@ fi
|
|||||||
echo "Step 2: Creating virtual environment..."
|
echo "Step 2: Creating virtual environment..."
|
||||||
cd "$PROJECT_ROOT"
|
cd "$PROJECT_ROOT"
|
||||||
if [ ! -d "venv" ]; then
|
if [ ! -d "venv" ]; then
|
||||||
python3 -m venv venv
|
python3 -m venv --system-site-packages venv
|
||||||
echo "Virtual environment created."
|
echo "Virtual environment created with system site packages access."
|
||||||
else
|
else
|
||||||
echo "Virtual environment already exists."
|
echo "Removing existing virtual environment and creating new one with system site packages..."
|
||||||
|
rm -rf venv
|
||||||
|
python3 -m venv --system-site-packages venv
|
||||||
|
echo "Virtual environment recreated with system site packages access."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Activate virtual environment
|
# Activate virtual environment
|
||||||
@@ -57,35 +60,38 @@ source venv/bin/activate
|
|||||||
|
|
||||||
# Install Python packages from offline wheels
|
# Install Python packages from offline wheels
|
||||||
echo "Step 4: Installing Python packages from offline wheels..."
|
echo "Step 4: Installing Python packages from offline wheels..."
|
||||||
if [ -d "src/offline_packages" ]; then
|
OFFLINE_PACKAGES_DIR="$PROJECT_ROOT/src/offline_packages"
|
||||||
|
if [ -d "$OFFLINE_PACKAGES_DIR" ]; then
|
||||||
pip install --upgrade pip
|
pip install --upgrade pip
|
||||||
pip install --no-index --find-links "src/offline_packages" \
|
pip install --no-index --find-links "$OFFLINE_PACKAGES_DIR" \
|
||||||
requests pillow pygame certifi charset_normalizer idna urllib3
|
requests pillow pygame certifi charset_normalizer idna urllib3
|
||||||
echo "Python packages installed successfully."
|
echo "Python packages installed successfully."
|
||||||
else
|
else
|
||||||
echo "ERROR: Offline packages directory not found!"
|
echo "ERROR: Offline packages directory not found at: $OFFLINE_PACKAGES_DIR"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Copy shared modules to tkinter app
|
# Copy shared modules to tkinter app
|
||||||
echo "Step 5: Setting up shared modules..."
|
echo "Step 5: Setting up shared modules..."
|
||||||
if [ -d "src/shared_modules" ]; then
|
SHARED_MODULES_DIR="$PROJECT_ROOT/src/shared_modules"
|
||||||
cp src/shared_modules/*.py tkinter_app/src/ 2>/dev/null || echo "Shared modules already in place."
|
TKINTER_APP_DIR="$PROJECT_ROOT/tkinter_app/src"
|
||||||
|
if [ -d "$SHARED_MODULES_DIR" ]; then
|
||||||
|
cp "$SHARED_MODULES_DIR"/*.py "$TKINTER_APP_DIR"/ 2>/dev/null || echo "Shared modules already in place."
|
||||||
echo "Shared modules configured."
|
echo "Shared modules configured."
|
||||||
else
|
else
|
||||||
echo "Warning: Shared modules directory not found."
|
echo "Warning: Shared modules directory not found at: $SHARED_MODULES_DIR"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create necessary directories
|
# Create necessary directories
|
||||||
echo "Step 6: Creating application directories..."
|
echo "Step 6: Creating application directories..."
|
||||||
mkdir -p tkinter_app/resources/static/resurse
|
mkdir -p "$PROJECT_ROOT/tkinter_app/resources/static/resurse"
|
||||||
mkdir -p tkinter_app/src/static/resurse
|
mkdir -p "$PROJECT_ROOT/tkinter_app/src/static/resurse"
|
||||||
|
|
||||||
# Set permissions
|
# Set permissions
|
||||||
echo "Step 7: Setting permissions..."
|
echo "Step 7: Setting permissions..."
|
||||||
chmod +x run_tkinter_debug.sh
|
chmod +x "$PROJECT_ROOT/run_tkinter_debug.sh" 2>/dev/null || true
|
||||||
chmod +x install_tkinter.sh
|
chmod +x "$PROJECT_ROOT/install_tkinter.sh" 2>/dev/null || true
|
||||||
chmod +x src/scripts/*.sh 2>/dev/null || true
|
chmod +x "$PROJECT_ROOT/src/scripts"/*.sh 2>/dev/null || true
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "=== Installation Complete! ==="
|
echo "=== Installation Complete! ==="
|
||||||
|
|||||||
143
test_centering.py
Normal file
143
test_centering.py
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test script to verify window centering functionality
|
||||||
|
"""
|
||||||
|
import tkinter as tk
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
sys.path.append('tkinter_app/src')
|
||||||
|
from tkinter_simple_player import SettingsWindow, SimpleMediaPlayerApp
|
||||||
|
|
||||||
|
def test_settings_centering():
|
||||||
|
"""Test settings window centering"""
|
||||||
|
root = tk.Tk()
|
||||||
|
root.withdraw() # Hide main window
|
||||||
|
|
||||||
|
# Create a mock app object
|
||||||
|
class MockApp:
|
||||||
|
def __init__(self):
|
||||||
|
self.playlist = []
|
||||||
|
self.current_index = 0
|
||||||
|
|
||||||
|
def play_current_media(self):
|
||||||
|
print('play_current_media called')
|
||||||
|
|
||||||
|
app = MockApp()
|
||||||
|
|
||||||
|
# Test settings window centering
|
||||||
|
try:
|
||||||
|
print("Testing settings window centering...")
|
||||||
|
settings = SettingsWindow(root, app)
|
||||||
|
|
||||||
|
# Get screen dimensions
|
||||||
|
screen_width = settings.window.winfo_screenwidth()
|
||||||
|
screen_height = settings.window.winfo_screenheight()
|
||||||
|
|
||||||
|
# Get window position
|
||||||
|
settings.window.update_idletasks()
|
||||||
|
window_x = settings.window.winfo_x()
|
||||||
|
window_y = settings.window.winfo_y()
|
||||||
|
window_width = 900
|
||||||
|
window_height = 700
|
||||||
|
|
||||||
|
# Calculate expected center position
|
||||||
|
expected_x = (screen_width - window_width) // 2
|
||||||
|
expected_y = (screen_height - window_height) // 2
|
||||||
|
|
||||||
|
print(f"Screen size: {screen_width}x{screen_height}")
|
||||||
|
print(f"Window position: {window_x}, {window_y}")
|
||||||
|
print(f"Expected center: {expected_x}, {expected_y}")
|
||||||
|
print(f"Window size: {window_width}x{window_height}")
|
||||||
|
|
||||||
|
# Check if window is roughly centered (allow some margin for window decorations)
|
||||||
|
margin = 50
|
||||||
|
is_centered_x = abs(window_x - expected_x) <= margin
|
||||||
|
is_centered_y = abs(window_y - expected_y) <= margin
|
||||||
|
|
||||||
|
if is_centered_x and is_centered_y:
|
||||||
|
print("✅ Settings window is properly centered!")
|
||||||
|
else:
|
||||||
|
print("❌ Settings window centering needs adjustment")
|
||||||
|
|
||||||
|
# Keep window open for 3 seconds to visually verify
|
||||||
|
root.after(3000, root.quit)
|
||||||
|
root.mainloop()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error testing settings window: {e}")
|
||||||
|
|
||||||
|
def test_exit_dialog_centering():
|
||||||
|
"""Test exit dialog centering"""
|
||||||
|
print("\nTesting exit dialog centering...")
|
||||||
|
|
||||||
|
# Create a simple test for the centering function
|
||||||
|
root = tk.Tk()
|
||||||
|
root.withdraw()
|
||||||
|
|
||||||
|
# Create a test dialog
|
||||||
|
dialog = tk.Toplevel(root)
|
||||||
|
dialog.title("Test Exit Dialog")
|
||||||
|
dialog.geometry("400x200")
|
||||||
|
dialog.configure(bg='#2d2d2d')
|
||||||
|
dialog.resizable(False, False)
|
||||||
|
|
||||||
|
# Test the centering logic
|
||||||
|
dialog.update_idletasks()
|
||||||
|
screen_width = dialog.winfo_screenwidth()
|
||||||
|
screen_height = dialog.winfo_screenheight()
|
||||||
|
dialog_width = 400
|
||||||
|
dialog_height = 200
|
||||||
|
|
||||||
|
# Calculate center position
|
||||||
|
center_x = int((screen_width - dialog_width) / 2)
|
||||||
|
center_y = int((screen_height - dialog_height) / 2)
|
||||||
|
|
||||||
|
# Ensure the dialog doesn't go off-screen
|
||||||
|
center_x = max(0, min(center_x, screen_width - dialog_width))
|
||||||
|
center_y = max(0, min(center_y, screen_height - dialog_height))
|
||||||
|
|
||||||
|
dialog.geometry(f"{dialog_width}x{dialog_height}+{center_x}+{center_y}")
|
||||||
|
dialog.lift()
|
||||||
|
|
||||||
|
# Add test content
|
||||||
|
tk.Label(dialog, text="🎬 Test Exit Dialog",
|
||||||
|
font=('Arial', 16, 'bold'),
|
||||||
|
fg='white', bg='#2d2d2d').pack(pady=20)
|
||||||
|
|
||||||
|
tk.Label(dialog, text="This dialog should be centered on screen",
|
||||||
|
font=('Arial', 12),
|
||||||
|
fg='white', bg='#2d2d2d').pack(pady=10)
|
||||||
|
|
||||||
|
# Get actual position
|
||||||
|
dialog.update_idletasks()
|
||||||
|
actual_x = dialog.winfo_x()
|
||||||
|
actual_y = dialog.winfo_y()
|
||||||
|
|
||||||
|
print(f"Screen size: {screen_width}x{screen_height}")
|
||||||
|
print(f"Dialog position: {actual_x}, {actual_y}")
|
||||||
|
print(f"Expected center: {center_x}, {center_y}")
|
||||||
|
|
||||||
|
# Check centering
|
||||||
|
margin = 50
|
||||||
|
is_centered_x = abs(actual_x - center_x) <= margin
|
||||||
|
is_centered_y = abs(actual_y - center_y) <= margin
|
||||||
|
|
||||||
|
if is_centered_x and is_centered_y:
|
||||||
|
print("✅ Exit dialog is properly centered!")
|
||||||
|
else:
|
||||||
|
print("❌ Exit dialog centering needs adjustment")
|
||||||
|
|
||||||
|
# Close dialog after 3 seconds
|
||||||
|
root.after(3000, root.quit)
|
||||||
|
root.mainloop()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("🧪 Testing Window Centering Functionality")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
test_settings_centering()
|
||||||
|
test_exit_dialog_centering()
|
||||||
|
|
||||||
|
print("\n✅ Centering tests completed!")
|
||||||
|
print("\nThe windows should appear centered on your screen regardless of resolution.")
|
||||||
|
print("This works for any screen size: 1024x768, 1920x1080, 4K, etc.")
|
||||||
54
test_image_display.py
Normal file
54
test_image_display.py
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test script to verify image display functionality
|
||||||
|
"""
|
||||||
|
import tkinter as tk
|
||||||
|
from PIL import Image, ImageTk
|
||||||
|
import os
|
||||||
|
|
||||||
|
def test_image_display():
|
||||||
|
# Create a simple tkinter window
|
||||||
|
root = tk.Tk()
|
||||||
|
root.title("Image Display Test")
|
||||||
|
root.geometry("800x600")
|
||||||
|
root.configure(bg='black')
|
||||||
|
|
||||||
|
# Create image label
|
||||||
|
image_label = tk.Label(root, bg='black')
|
||||||
|
image_label.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
# Test image path
|
||||||
|
test_image = "/home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg"
|
||||||
|
|
||||||
|
try:
|
||||||
|
if os.path.exists(test_image):
|
||||||
|
print(f"Loading image: {test_image}")
|
||||||
|
|
||||||
|
# Load and display image
|
||||||
|
img = Image.open(test_image)
|
||||||
|
img.thumbnail((800, 600), Image.LANCZOS)
|
||||||
|
photo = ImageTk.PhotoImage(img)
|
||||||
|
|
||||||
|
image_label.config(image=photo)
|
||||||
|
image_label.image = photo # Keep reference
|
||||||
|
|
||||||
|
print(f"Image loaded successfully: {img.size}")
|
||||||
|
|
||||||
|
# Close after 3 seconds
|
||||||
|
root.after(3000, root.quit)
|
||||||
|
|
||||||
|
else:
|
||||||
|
print(f"Image file not found: {test_image}")
|
||||||
|
image_label.config(text="Image file not found", fg='white')
|
||||||
|
root.after(2000, root.quit)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error loading image: {e}")
|
||||||
|
image_label.config(text=f"Error: {e}", fg='red')
|
||||||
|
root.after(2000, root.quit)
|
||||||
|
|
||||||
|
root.mainloop()
|
||||||
|
print("Image display test completed")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_image_display()
|
||||||
38
test_imports.py
Normal file
38
test_imports.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import sys
|
||||||
|
print("Testing imports...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
import tkinter as tk
|
||||||
|
print("✓ tkinter imported successfully")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ tkinter import failed: {e}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
from PIL import Image, ImageTk
|
||||||
|
print("✓ PIL and ImageTk imported successfully")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ PIL import failed: {e}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
from virtual_keyboard import VirtualKeyboard
|
||||||
|
print("✓ Virtual keyboard imported successfully")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Virtual keyboard import failed: {e}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
from python_functions import load_local_playlist
|
||||||
|
print("✓ Python functions imported successfully")
|
||||||
|
|
||||||
|
# Test loading playlist
|
||||||
|
playlist_data = load_local_playlist()
|
||||||
|
playlist = playlist_data.get('playlist', [])
|
||||||
|
print(f"✓ Local playlist loaded: {len(playlist)} items")
|
||||||
|
|
||||||
|
for i, item in enumerate(playlist):
|
||||||
|
print(f" {i+1}. {item.get('file_name', 'Unknown')}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Python functions import/execution failed: {e}")
|
||||||
|
|
||||||
|
print("Import test completed")
|
||||||
97
test_scaling.py
Normal file
97
test_scaling.py
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test script for full-screen image scaling functionality
|
||||||
|
"""
|
||||||
|
import tkinter as tk
|
||||||
|
from PIL import Image, ImageTk
|
||||||
|
import os
|
||||||
|
|
||||||
|
def test_scaling_modes():
|
||||||
|
"""Test different scaling modes for images"""
|
||||||
|
|
||||||
|
def scale_image_to_screen(img, screen_width, screen_height, mode='fit'):
|
||||||
|
"""Test scaling function"""
|
||||||
|
img_width, img_height = img.size
|
||||||
|
|
||||||
|
if mode == 'stretch':
|
||||||
|
return img.resize((screen_width, screen_height), Image.LANCZOS), (0, 0)
|
||||||
|
|
||||||
|
elif mode == 'fill':
|
||||||
|
screen_ratio = screen_width / screen_height
|
||||||
|
img_ratio = img_width / img_height
|
||||||
|
|
||||||
|
if img_ratio > screen_ratio:
|
||||||
|
new_height = screen_height
|
||||||
|
new_width = int(screen_height * img_ratio)
|
||||||
|
x_offset = (screen_width - new_width) // 2
|
||||||
|
y_offset = 0
|
||||||
|
else:
|
||||||
|
new_width = screen_width
|
||||||
|
new_height = int(screen_width / img_ratio)
|
||||||
|
x_offset = 0
|
||||||
|
y_offset = (screen_height - new_height) // 2
|
||||||
|
|
||||||
|
img_resized = img.resize((new_width, new_height), Image.LANCZOS)
|
||||||
|
final_img = Image.new('RGB', (screen_width, screen_height), 'black')
|
||||||
|
|
||||||
|
if new_width > screen_width:
|
||||||
|
crop_x = (new_width - screen_width) // 2
|
||||||
|
img_resized = img_resized.crop((crop_x, 0, crop_x + screen_width, new_height))
|
||||||
|
x_offset = 0
|
||||||
|
if new_height > screen_height:
|
||||||
|
crop_y = (new_height - screen_height) // 2
|
||||||
|
img_resized = img_resized.crop((0, crop_y, new_width, crop_y + screen_height))
|
||||||
|
y_offset = 0
|
||||||
|
|
||||||
|
final_img.paste(img_resized, (x_offset, y_offset))
|
||||||
|
return final_img, (x_offset, y_offset)
|
||||||
|
|
||||||
|
else: # fit mode
|
||||||
|
screen_ratio = screen_width / screen_height
|
||||||
|
img_ratio = img_width / img_height
|
||||||
|
|
||||||
|
if img_ratio > screen_ratio:
|
||||||
|
new_width = screen_width
|
||||||
|
new_height = int(screen_width / img_ratio)
|
||||||
|
else:
|
||||||
|
new_height = screen_height
|
||||||
|
new_width = int(screen_height * img_ratio)
|
||||||
|
|
||||||
|
img_resized = img.resize((new_width, new_height), Image.LANCZOS)
|
||||||
|
final_img = Image.new('RGB', (screen_width, screen_height), 'black')
|
||||||
|
x_offset = (screen_width - new_width) // 2
|
||||||
|
y_offset = (screen_height - new_height) // 2
|
||||||
|
final_img.paste(img_resized, (x_offset, y_offset))
|
||||||
|
|
||||||
|
return final_img, (x_offset, y_offset)
|
||||||
|
|
||||||
|
# Test image path
|
||||||
|
test_image = "/home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg"
|
||||||
|
|
||||||
|
if not os.path.exists(test_image):
|
||||||
|
print(f"Test image not found: {test_image}")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Load test image
|
||||||
|
img = Image.open(test_image)
|
||||||
|
original_size = img.size
|
||||||
|
screen_width, screen_height = 800, 600
|
||||||
|
|
||||||
|
print(f"Testing scaling modes for image: {original_size}")
|
||||||
|
print(f"Target screen size: {screen_width}x{screen_height}")
|
||||||
|
|
||||||
|
# Test each scaling mode
|
||||||
|
modes = ['fit', 'fill', 'stretch']
|
||||||
|
|
||||||
|
for mode in modes:
|
||||||
|
final_img, offset = scale_image_to_screen(img, screen_width, screen_height, mode)
|
||||||
|
print(f"{mode.upper()} mode: Final size: {final_img.size}, Offset: {offset}")
|
||||||
|
|
||||||
|
print("✅ All scaling modes tested successfully!")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error testing scaling: {e}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_scaling_modes()
|
||||||
230
test_touch.py
Normal file
230
test_touch.py
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Touch Display Test - Test the touch-optimized interface with virtual keyboard
|
||||||
|
"""
|
||||||
|
import tkinter as tk
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
sys.path.append('tkinter_app/src')
|
||||||
|
|
||||||
|
def test_touch_interface():
|
||||||
|
"""Test the touch-optimized settings interface"""
|
||||||
|
try:
|
||||||
|
from tkinter_simple_player import SettingsWindow
|
||||||
|
|
||||||
|
# Create main window
|
||||||
|
root = tk.Tk()
|
||||||
|
root.title("🎮 Touch Display Test")
|
||||||
|
root.geometry("1024x768")
|
||||||
|
root.configure(bg='#2c3e50')
|
||||||
|
|
||||||
|
# Create welcome screen
|
||||||
|
welcome_frame = tk.Frame(root, bg='#2c3e50', padx=40, pady=40)
|
||||||
|
welcome_frame.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
# Title
|
||||||
|
title_label = tk.Label(welcome_frame,
|
||||||
|
text="🎬 Touch Display Digital Signage",
|
||||||
|
font=('Segoe UI', 24, 'bold'),
|
||||||
|
fg='white', bg='#2c3e50')
|
||||||
|
title_label.pack(pady=30)
|
||||||
|
|
||||||
|
# Description
|
||||||
|
desc_text = (
|
||||||
|
"Touch-Optimized Features:\n\n"
|
||||||
|
"📱 Virtual On-Screen Keyboard\n"
|
||||||
|
"🎯 Larger Touch-Friendly Buttons\n"
|
||||||
|
"⌨️ Auto-Show Keyboard on Input Focus\n"
|
||||||
|
"👆 Enhanced Touch Feedback\n"
|
||||||
|
"🎨 Dark Theme Optimized for Displays\n\n"
|
||||||
|
"Click the button below to test the settings interface:"
|
||||||
|
)
|
||||||
|
|
||||||
|
desc_label = tk.Label(welcome_frame, text=desc_text,
|
||||||
|
font=('Segoe UI', 14),
|
||||||
|
fg='#ecf0f1', bg='#2c3e50',
|
||||||
|
justify=tk.CENTER)
|
||||||
|
desc_label.pack(pady=20)
|
||||||
|
|
||||||
|
# Create mock app for testing
|
||||||
|
class MockApp:
|
||||||
|
def __init__(self):
|
||||||
|
self.playlist = []
|
||||||
|
self.current_index = 0
|
||||||
|
|
||||||
|
def play_current_media(self):
|
||||||
|
print("Mock: play_current_media called")
|
||||||
|
|
||||||
|
mock_app = MockApp()
|
||||||
|
|
||||||
|
# Test button to open touch-optimized settings
|
||||||
|
def open_touch_settings():
|
||||||
|
try:
|
||||||
|
settings = SettingsWindow(root, mock_app)
|
||||||
|
print("✅ Touch-optimized settings window opened successfully!")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error opening settings: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
# Large touch-friendly button
|
||||||
|
settings_btn = tk.Button(welcome_frame,
|
||||||
|
text="🔧 Open Touch Settings",
|
||||||
|
command=open_touch_settings,
|
||||||
|
bg='#3498db', fg='white',
|
||||||
|
font=('Segoe UI', 16, 'bold'),
|
||||||
|
relief=tk.FLAT, padx=40, pady=20,
|
||||||
|
cursor='hand2')
|
||||||
|
settings_btn.pack(pady=30)
|
||||||
|
|
||||||
|
# Instructions
|
||||||
|
instructions = (
|
||||||
|
"Touch Instructions:\n"
|
||||||
|
"• Tap input fields to show virtual keyboard\n"
|
||||||
|
"• Use large buttons for easy touch interaction\n"
|
||||||
|
"• Virtual keyboard stays on top for easy access\n"
|
||||||
|
"• Click outside input fields to hide keyboard"
|
||||||
|
)
|
||||||
|
|
||||||
|
instr_label = tk.Label(welcome_frame, text=instructions,
|
||||||
|
font=('Segoe UI', 11),
|
||||||
|
fg='#bdc3c7', bg='#2c3e50',
|
||||||
|
justify=tk.LEFT)
|
||||||
|
instr_label.pack(pady=20)
|
||||||
|
|
||||||
|
# Exit button
|
||||||
|
exit_btn = tk.Button(welcome_frame,
|
||||||
|
text="❌ Exit Test",
|
||||||
|
command=root.quit,
|
||||||
|
bg='#e74c3c', fg='white',
|
||||||
|
font=('Segoe UI', 12, 'bold'),
|
||||||
|
relief=tk.FLAT, padx=30, pady=15,
|
||||||
|
cursor='hand2')
|
||||||
|
exit_btn.pack(pady=20)
|
||||||
|
|
||||||
|
# Add touch feedback to buttons
|
||||||
|
def add_touch_feedback(button):
|
||||||
|
def on_press(e):
|
||||||
|
button.configure(relief=tk.SUNKEN)
|
||||||
|
def on_release(e):
|
||||||
|
button.configure(relief=tk.FLAT)
|
||||||
|
def on_enter(e):
|
||||||
|
button.configure(relief=tk.RAISED)
|
||||||
|
def on_leave(e):
|
||||||
|
button.configure(relief=tk.FLAT)
|
||||||
|
|
||||||
|
button.bind("<Button-1>", on_press)
|
||||||
|
button.bind("<ButtonRelease-1>", on_release)
|
||||||
|
button.bind("<Enter>", on_enter)
|
||||||
|
button.bind("<Leave>", on_leave)
|
||||||
|
|
||||||
|
add_touch_feedback(settings_btn)
|
||||||
|
add_touch_feedback(exit_btn)
|
||||||
|
|
||||||
|
print("🎮 Touch Display Test Started")
|
||||||
|
print("=" * 50)
|
||||||
|
print("Features being tested:")
|
||||||
|
print("- Virtual keyboard integration")
|
||||||
|
print("- Touch-optimized input fields")
|
||||||
|
print("- Large, finger-friendly buttons")
|
||||||
|
print("- Enhanced visual feedback")
|
||||||
|
print("- Dark theme for displays")
|
||||||
|
print("\nClick 'Open Touch Settings' to test the interface!")
|
||||||
|
|
||||||
|
root.mainloop()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error in touch interface test: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
def test_virtual_keyboard_standalone():
|
||||||
|
"""Test just the virtual keyboard component"""
|
||||||
|
try:
|
||||||
|
from virtual_keyboard import VirtualKeyboard, TouchOptimizedEntry, TouchOptimizedButton
|
||||||
|
|
||||||
|
root = tk.Tk()
|
||||||
|
root.title("🎹 Virtual Keyboard Test")
|
||||||
|
root.geometry("800x500")
|
||||||
|
root.configure(bg='#2f3136')
|
||||||
|
|
||||||
|
# Create virtual keyboard
|
||||||
|
vk = VirtualKeyboard(root, dark_theme=True)
|
||||||
|
|
||||||
|
# Test interface
|
||||||
|
test_frame = tk.Frame(root, bg='#2f3136', padx=30, pady=30)
|
||||||
|
test_frame.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
tk.Label(test_frame, text="🎹 Virtual Keyboard Test",
|
||||||
|
font=('Segoe UI', 20, 'bold'),
|
||||||
|
bg='#2f3136', fg='white').pack(pady=20)
|
||||||
|
|
||||||
|
tk.Label(test_frame, text="Click on the input fields below to test the virtual keyboard:",
|
||||||
|
font=('Segoe UI', 12),
|
||||||
|
bg='#2f3136', fg='#b9bbbe').pack(pady=10)
|
||||||
|
|
||||||
|
# Test input fields
|
||||||
|
tk.Label(test_frame, text="Server IP:", bg='#2f3136', fg='white',
|
||||||
|
font=('Segoe UI', 11, 'bold')).pack(anchor=tk.W, pady=(20, 5))
|
||||||
|
entry1 = TouchOptimizedEntry(test_frame, vk, width=40, bg='#36393f',
|
||||||
|
fg='white', insertbackground='white')
|
||||||
|
entry1.pack(pady=5, fill=tk.X)
|
||||||
|
|
||||||
|
tk.Label(test_frame, text="Device Name:", bg='#2f3136', fg='white',
|
||||||
|
font=('Segoe UI', 11, 'bold')).pack(anchor=tk.W, pady=(15, 5))
|
||||||
|
entry2 = TouchOptimizedEntry(test_frame, vk, width=40, bg='#36393f',
|
||||||
|
fg='white', insertbackground='white')
|
||||||
|
entry2.pack(pady=5, fill=tk.X)
|
||||||
|
|
||||||
|
tk.Label(test_frame, text="Password:", bg='#2f3136', fg='white',
|
||||||
|
font=('Segoe UI', 11, 'bold')).pack(anchor=tk.W, pady=(15, 5))
|
||||||
|
entry3 = TouchOptimizedEntry(test_frame, vk, width=40, bg='#36393f',
|
||||||
|
fg='white', insertbackground='white', show='*')
|
||||||
|
entry3.pack(pady=5, fill=tk.X)
|
||||||
|
|
||||||
|
# Control buttons
|
||||||
|
btn_frame = tk.Frame(test_frame, bg='#2f3136')
|
||||||
|
btn_frame.pack(pady=30)
|
||||||
|
|
||||||
|
TouchOptimizedButton(btn_frame, text="🎹 Show Keyboard",
|
||||||
|
command=lambda: vk.show_keyboard(entry1),
|
||||||
|
bg='#7289da', fg='white').pack(side=tk.LEFT, padx=10)
|
||||||
|
|
||||||
|
TouchOptimizedButton(btn_frame, text="❌ Hide Keyboard",
|
||||||
|
command=vk.hide_keyboard,
|
||||||
|
bg='#ed4245', fg='white').pack(side=tk.LEFT, padx=10)
|
||||||
|
|
||||||
|
TouchOptimizedButton(btn_frame, text="🔄 Clear All",
|
||||||
|
command=lambda: [e.delete(0, tk.END) for e in [entry1, entry2, entry3]],
|
||||||
|
bg='#faa61a', fg='white').pack(side=tk.LEFT, padx=10)
|
||||||
|
|
||||||
|
print("🎹 Virtual Keyboard Test Started")
|
||||||
|
print("- Click input fields to auto-show keyboard")
|
||||||
|
print("- Type using virtual or physical keyboard")
|
||||||
|
print("- Test touch-friendly interface")
|
||||||
|
|
||||||
|
root.mainloop()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error in virtual keyboard test: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description="Touch Display Tests")
|
||||||
|
parser.add_argument("--keyboard-only", action="store_true",
|
||||||
|
help="Test only the virtual keyboard component")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
print("🎮 Touch Display Digital Signage Tests")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
if args.keyboard_only:
|
||||||
|
test_virtual_keyboard_standalone()
|
||||||
|
else:
|
||||||
|
test_touch_interface()
|
||||||
|
|
||||||
|
print("\n✅ Touch display tests completed!")
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"screen_orientation": "Landscape",
|
"screen_orientation": "Landscape",
|
||||||
"screen_name": "tv-holba1",
|
"screen_name": "tv-terasa",
|
||||||
"quickconnect_key": "8887779",
|
"quickconnect_key": "8887779",
|
||||||
"server_ip": "192.168.1.245",
|
"server_ip": "digi-signage.moto-adv.com",
|
||||||
"port": "5000",
|
"port": "8880",
|
||||||
"screen_w": "1920",
|
"screen_w": "1920",
|
||||||
"screen_h": "1080",
|
"screen_h": "1080",
|
||||||
"playlist_version": 5
|
"playlist_version": 5
|
||||||
|
|||||||
@@ -859,3 +859,328 @@
|
|||||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
[INFO] [SignageApp] Application exit requested
|
[INFO] [SignageApp] Application exit requested
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration loaded: server=192.168.1.245, host=tv-holba1, quick=8887779, port=5000
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_local_playlist function.
|
||||||
|
[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': '1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'url': 'static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'duration': 20}, {'file_name': 'wp2782770-1846651530.jpg', 'url': 'static/resurse/wp2782770-1846651530.jpg', 'duration': 15}, {'file_name': 'SampleVideo_1280x720_1mb.mp4', 'url': 'static/resurse/SampleVideo_1280x720_1mb.mp4', 'duration': 5}], 'version': 5}
|
||||||
|
[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully.
|
||||||
|
[INFO] [SignageApp] Found fallback playlist with 3 items
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Initializing with settings: server=192.168.1.245, host=tv-holba1, port=5000
|
||||||
|
[INFO] [SignageApp] Attempting to connect to server...
|
||||||
|
[INFO] [SignageApp] Fetching playlist from URL: http://192.168.1.245:5000/api/playlists with params: {'hostname': 'tv-holba1', 'quickconnect_code': '8887779'}
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-server.moto-adv.com, host=tv-terasa, quick=8887779, port=8880
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_local_playlist function.
|
||||||
|
[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': '1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'url': 'static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'duration': 20}, {'file_name': 'wp2782770-1846651530.jpg', 'url': 'static/resurse/wp2782770-1846651530.jpg', 'duration': 15}, {'file_name': 'SampleVideo_1280x720_1mb.mp4', 'url': 'static/resurse/SampleVideo_1280x720_1mb.mp4', 'duration': 5}], 'version': 5}
|
||||||
|
[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully.
|
||||||
|
[INFO] [SignageApp] Found fallback playlist with 3 items
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Initializing with settings: server=digi-server.moto-adv.com, host=tv-terasa, port=8880
|
||||||
|
[INFO] [SignageApp] Attempting to connect to server...
|
||||||
|
[INFO] [SignageApp] Fetching playlist from URL: http://digi-server.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||||
|
[ERROR] [SignageApp] Failed to fetch playlist: HTTPConnectionPool(host='digi-server.moto-adv.com', port=8880): Max retries exceeded with url: /api/playlists?hostname=tv-terasa&quickconnect_code=8887779 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0xd59e9190>: Failed to establish a new connection: [Errno -2] Name or service not known'))
|
||||||
|
[WARNING] [SignageApp] Server returned empty playlist, falling back to local playlist
|
||||||
|
[INFO] [SignageApp] Loaded fallback playlist with 3 items
|
||||||
|
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
2025-08-05 19:12:35 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
[INFO] [SignageApp] Starting Simple Tkinter Media Player
|
||||||
|
[INFO] [SignageApp] Loading configuration in settings window
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Config loaded: {'screen_orientation': 'Landscape', 'screen_name': 'tv-terasa', 'quickconnect_key': '8887779', 'server_ip': 'digi-server.moto-adv.com', 'port': '8880', 'screen_w': '1920', 'screen_h': '1080', 'playlist_version': 5}
|
||||||
|
[INFO] [SignageApp] Configuration values loaded successfully in settings
|
||||||
|
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||||
|
2025-08-05 19:12:55 - STARTED: wp2782770-1846651530.jpg
|
||||||
|
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||||
|
2025-08-05 19:13:10 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||||
|
[ERROR] [SignageApp] Error playing video /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4: name 'ImageTk' is not defined
|
||||||
|
[INFO] [SignageApp] Fetching playlist from URL: http://digi-server.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||||
|
[ERROR] [SignageApp] Failed to fetch playlist: HTTPConnectionPool(host='digi-server.moto-adv.com', port=8880): Max retries exceeded with url: /api/playlists?hostname=tv-terasa&quickconnect_code=8887779 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0xd59fe590>: Failed to establish a new connection: [Errno -2] Name or service not known'))
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
2025-08-05 19:13:16 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
[INFO] [SignageApp] Fetching playlist from URL: http://digi-server.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||||
|
[ERROR] [SignageApp] Failed to fetch playlist: HTTPConnectionPool(host='digi-server.moto-adv.com', port=8880): Max retries exceeded with url: /api/playlists?hostname=tv-terasa&quickconnect_code=8887779 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0xd59e94d0>: Failed to establish a new connection: [Errno -2] Name or service not known'))
|
||||||
|
[INFO] [SignageApp] No playlist updates available
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Application exit requested
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-server.moto-adv.com, host=tv-terasa, quick=8887779, port=8880
|
||||||
|
[INFO] [SignageApp] Loading configuration in settings window
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Config loaded: {'screen_orientation': 'Landscape', 'screen_name': 'tv-terasa', 'quickconnect_key': '8887779', 'server_ip': 'digi-server.moto-adv.com', 'port': '8880', 'screen_w': '1920', 'screen_h': '1080', 'playlist_version': 5}
|
||||||
|
[INFO] [SignageApp] Configuration values loaded successfully in settings
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-server.moto-adv.com, host=tv-terasa, quick=8887779, port=8880
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_local_playlist function.
|
||||||
|
[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': '1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'url': 'static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'duration': 20}, {'file_name': 'wp2782770-1846651530.jpg', 'url': 'static/resurse/wp2782770-1846651530.jpg', 'duration': 15}, {'file_name': 'SampleVideo_1280x720_1mb.mp4', 'url': 'static/resurse/SampleVideo_1280x720_1mb.mp4', 'duration': 5}], 'version': 5}
|
||||||
|
[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully.
|
||||||
|
[INFO] [SignageApp] Found fallback playlist with 3 items
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Initializing with settings: server=digi-server.moto-adv.com, host=tv-terasa, port=8880
|
||||||
|
[INFO] [SignageApp] Attempting to connect to server...
|
||||||
|
[INFO] [SignageApp] Fetching playlist from URL: http://digi-server.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||||
|
[ERROR] [SignageApp] Failed to fetch playlist: HTTPConnectionPool(host='digi-server.moto-adv.com', port=8880): Max retries exceeded with url: /api/playlists?hostname=tv-terasa&quickconnect_code=8887779 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0xd5cf6670>: Failed to establish a new connection: [Errno -2] Name or service not known'))
|
||||||
|
[WARNING] [SignageApp] Server returned empty playlist, falling back to local playlist
|
||||||
|
[INFO] [SignageApp] Loaded fallback playlist with 3 items
|
||||||
|
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
2025-08-06 01:11:39 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
[INFO] [SignageApp] Starting Simple Tkinter Media Player
|
||||||
|
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||||
|
2025-08-06 01:11:59 - STARTED: wp2782770-1846651530.jpg
|
||||||
|
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||||
|
2025-08-06 01:12:14 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||||
|
[ERROR] [SignageApp] Error playing video /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4: name 'ImageTk' is not defined
|
||||||
|
[INFO] [SignageApp] Loading configuration in settings window
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Config loaded: {'screen_orientation': 'Landscape', 'screen_name': 'tv-terasa', 'quickconnect_key': '8887779', 'server_ip': 'digi-server.moto-adv.com', 'port': '8880', 'screen_w': '1920', 'screen_h': '1080', 'playlist_version': 5}
|
||||||
|
[INFO] [SignageApp] Configuration values loaded successfully in settings
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
2025-08-06 01:12:20 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
[INFO] [SignageApp] Fetching playlist from URL: http://digi-server.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||||
|
[ERROR] [SignageApp] Failed to fetch playlist: HTTPConnectionPool(host='digi-server.moto-adv.com', port=8880): Max retries exceeded with url: /api/playlists?hostname=tv-terasa&quickconnect_code=8887779 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0xd5d07670>: Failed to establish a new connection: [Errno -2] Name or service not known'))
|
||||||
|
[INFO] [SignageApp] No playlist updates available
|
||||||
|
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||||
|
2025-08-06 01:12:40 - STARTED: wp2782770-1846651530.jpg
|
||||||
|
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||||
|
2025-08-06 01:12:55 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||||
|
[ERROR] [SignageApp] Error playing video /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4: name 'ImageTk' is not defined
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
2025-08-06 01:13:00 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Fetching playlist from URL: http://digi-server.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||||
|
[ERROR] [SignageApp] Failed to fetch playlist: HTTPConnectionPool(host='digi-server.moto-adv.com', port=8880): Max retries exceeded with url: /api/playlists?hostname=tv-terasa&quickconnect_code=8887779 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0xd5d00570>: Failed to establish a new connection: [Errno -2] Name or service not known'))
|
||||||
|
[INFO] [SignageApp] No playlist updates available
|
||||||
|
[INFO] [SignageApp] Application exit requested
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-server.moto-adv.com, host=tv-terasa, quick=8887779, port=8880
|
||||||
|
[INFO] [SignageApp] Loading configuration in enhanced settings window
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Config loaded: {'screen_orientation': 'Landscape', 'screen_name': 'tv-terasa', 'quickconnect_key': '8887779', 'server_ip': 'digi-server.moto-adv.com', 'port': '8880', 'screen_w': '1920', 'screen_h': '1080', 'playlist_version': 5}
|
||||||
|
[INFO] [SignageApp] Configuration values loaded successfully in enhanced settings
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-server.moto-adv.com, host=tv-terasa, quick=8887779, port=8880
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_local_playlist function.
|
||||||
|
[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': '1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'url': 'static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'duration': 20}, {'file_name': 'wp2782770-1846651530.jpg', 'url': 'static/resurse/wp2782770-1846651530.jpg', 'duration': 15}, {'file_name': 'SampleVideo_1280x720_1mb.mp4', 'url': 'static/resurse/SampleVideo_1280x720_1mb.mp4', 'duration': 5}], 'version': 5}
|
||||||
|
[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully.
|
||||||
|
[INFO] [SignageApp] Found fallback playlist with 3 items
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Initializing with settings: server=digi-server.moto-adv.com, host=tv-terasa, port=8880
|
||||||
|
[INFO] [SignageApp] Attempting to connect to server...
|
||||||
|
[INFO] [SignageApp] Fetching playlist from URL: http://digi-server.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||||
|
[ERROR] [SignageApp] Failed to fetch playlist: HTTPConnectionPool(host='digi-server.moto-adv.com', port=8880): Max retries exceeded with url: /api/playlists?hostname=tv-terasa&quickconnect_code=8887779 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0xd5c15e30>: Failed to establish a new connection: [Errno -2] Name or service not known'))
|
||||||
|
[WARNING] [SignageApp] Server returned empty playlist, falling back to local playlist
|
||||||
|
[INFO] [SignageApp] Loaded fallback playlist with 3 items
|
||||||
|
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
2025-08-06 01:31:08 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
[INFO] [SignageApp] Starting Simple Tkinter Media Player
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||||
|
2025-08-06 01:31:28 - STARTED: wp2782770-1846651530.jpg
|
||||||
|
[INFO] [SignageApp] Application exit requested
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-server.moto-adv.com, host=tv-terasa, quick=8887779, port=8880
|
||||||
|
[INFO] [SignageApp] Loading configuration in enhanced settings window
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Config loaded: {'screen_orientation': 'Landscape', 'screen_name': 'tv-terasa', 'quickconnect_key': '8887779', 'server_ip': 'digi-server.moto-adv.com', 'port': '8880', 'screen_w': '1920', 'screen_h': '1080', 'playlist_version': 5}
|
||||||
|
[INFO] [SignageApp] Configuration values loaded successfully in enhanced settings
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-server.moto-adv.com, host=tv-terasa, quick=8887779, port=8880
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-server.moto-adv.com, host=tv-terasa, quick=8887779, port=8880
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_local_playlist function.
|
||||||
|
[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': '1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'url': 'static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'duration': 20}, {'file_name': 'wp2782770-1846651530.jpg', 'url': 'static/resurse/wp2782770-1846651530.jpg', 'duration': 15}, {'file_name': 'SampleVideo_1280x720_1mb.mp4', 'url': 'static/resurse/SampleVideo_1280x720_1mb.mp4', 'duration': 5}], 'version': 5}
|
||||||
|
[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully.
|
||||||
|
[INFO] [SignageApp] Found fallback playlist with 3 items
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Initializing with settings: server=digi-server.moto-adv.com, host=tv-terasa, port=8880
|
||||||
|
[INFO] [SignageApp] Attempting to connect to server...
|
||||||
|
[INFO] [SignageApp] Fetching playlist from URL: http://digi-server.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||||
|
[ERROR] [SignageApp] Failed to fetch playlist: HTTPConnectionPool(host='digi-server.moto-adv.com', port=8880): Max retries exceeded with url: /api/playlists?hostname=tv-terasa&quickconnect_code=8887779 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0xd5b844f0>: Failed to establish a new connection: [Errno -2] Name or service not known'))
|
||||||
|
[WARNING] [SignageApp] Server returned empty playlist, falling back to local playlist
|
||||||
|
[INFO] [SignageApp] Loaded fallback playlist with 3 items
|
||||||
|
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
2025-08-06 01:51:49 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
[INFO] [SignageApp] Starting Simple Tkinter Media Player
|
||||||
|
[INFO] [SignageApp] Loading configuration in enhanced settings window
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Config loaded: {'screen_orientation': 'Landscape', 'screen_name': 'tv-terasa', 'quickconnect_key': '8887779', 'server_ip': 'digi-server.moto-adv.com', 'port': '8880', 'screen_w': '1920', 'screen_h': '1080', 'playlist_version': 5}
|
||||||
|
[INFO] [SignageApp] Configuration values loaded successfully in enhanced settings
|
||||||
|
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||||
|
2025-08-06 01:52:09 - STARTED: wp2782770-1846651530.jpg
|
||||||
|
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||||
|
2025-08-06 01:52:24 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||||
|
[ERROR] [SignageApp] Error playing video /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4: name 'ImageTk' is not defined
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
2025-08-06 01:52:30 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
[INFO] [SignageApp] Fetching playlist from URL: http://digi-server.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||||
|
[ERROR] [SignageApp] Failed to fetch playlist: HTTPConnectionPool(host='digi-server.moto-adv.com', port=8880): Max retries exceeded with url: /api/playlists?hostname=tv-terasa&quickconnect_code=8887779 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0xd5a552b0>: Failed to establish a new connection: [Errno -2] Name or service not known'))
|
||||||
|
[INFO] [SignageApp] No playlist updates available
|
||||||
|
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||||
|
2025-08-06 01:52:50 - STARTED: wp2782770-1846651530.jpg
|
||||||
|
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||||
|
2025-08-06 01:53:05 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||||
|
[ERROR] [SignageApp] Error playing video /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4: name 'ImageTk' is not defined
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
2025-08-06 01:53:05 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
[INFO] [SignageApp] Fetching playlist from URL: http://digi-server.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||||
|
[ERROR] [SignageApp] Failed to fetch playlist: HTTPConnectionPool(host='digi-server.moto-adv.com', port=8880): Max retries exceeded with url: /api/playlists?hostname=tv-terasa&quickconnect_code=8887779 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0xd5a29970>: Failed to establish a new connection: [Errno -2] Name or service not known'))
|
||||||
|
[INFO] [SignageApp] No playlist updates available
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Application exit requested
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-server.moto-adv.com, host=tv-terasa, quick=8887779, port=8880
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_local_playlist function.
|
||||||
|
[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': '1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'url': 'static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'duration': 20}, {'file_name': 'wp2782770-1846651530.jpg', 'url': 'static/resurse/wp2782770-1846651530.jpg', 'duration': 15}, {'file_name': 'SampleVideo_1280x720_1mb.mp4', 'url': 'static/resurse/SampleVideo_1280x720_1mb.mp4', 'duration': 5}], 'version': 5}
|
||||||
|
[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-server.moto-adv.com, host=tv-terasa, quick=8887779, port=8880
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_local_playlist function.
|
||||||
|
[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': '1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'url': 'static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'duration': 20}, {'file_name': 'wp2782770-1846651530.jpg', 'url': 'static/resurse/wp2782770-1846651530.jpg', 'duration': 15}, {'file_name': 'SampleVideo_1280x720_1mb.mp4', 'url': 'static/resurse/SampleVideo_1280x720_1mb.mp4', 'duration': 5}], 'version': 5}
|
||||||
|
[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully.
|
||||||
|
[INFO] [SignageApp] Found fallback playlist with 3 items
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Initializing with settings: server=digi-server.moto-adv.com, host=tv-terasa, port=8880
|
||||||
|
[INFO] [SignageApp] Attempting to connect to server...
|
||||||
|
[INFO] [SignageApp] Fetching playlist from URL: http://digi-server.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||||
|
[ERROR] [SignageApp] Failed to fetch playlist: HTTPConnectionPool(host='digi-server.moto-adv.com', port=8880): Max retries exceeded with url: /api/playlists?hostname=tv-terasa&quickconnect_code=8887779 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0xd586dfb0>: Failed to establish a new connection: [Errno -2] Name or service not known'))
|
||||||
|
[WARNING] [SignageApp] Server returned empty playlist, falling back to local playlist
|
||||||
|
[INFO] [SignageApp] Loaded fallback playlist with 3 items
|
||||||
|
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
2025-08-06 02:02:39 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg ((1600, 1000))
|
||||||
|
[INFO] [SignageApp] Starting Simple Tkinter Media Player
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Application exit requested
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_local_playlist function.
|
||||||
|
[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': '1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'url': 'static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'duration': 20}, {'file_name': 'wp2782770-1846651530.jpg', 'url': 'static/resurse/wp2782770-1846651530.jpg', 'duration': 15}, {'file_name': 'SampleVideo_1280x720_1mb.mp4', 'url': 'static/resurse/SampleVideo_1280x720_1mb.mp4', 'duration': 5}], 'version': 5}
|
||||||
|
[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully.
|
||||||
|
[INFO] [SignageApp] Found fallback playlist with 3 items
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Initializing with settings: server=digi-signage.moto-adv.com, host=tv-terasa, port=8880
|
||||||
|
[INFO] [SignageApp] Attempting to connect to server...
|
||||||
|
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||||
|
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||||
|
[WARNING] [SignageApp] Server returned empty playlist, falling back to local playlist
|
||||||
|
[INFO] [SignageApp] Loading configuration in enhanced settings window
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Config loaded: {'screen_orientation': 'Landscape', 'screen_name': 'tv-terasa', 'quickconnect_key': '8887779', 'server_ip': 'digi-signage.moto-adv.com', 'port': '8880', 'screen_w': '1920', 'screen_h': '1080', 'playlist_version': 5}
|
||||||
|
[INFO] [SignageApp] Configuration values loaded successfully in enhanced settings
|
||||||
|
[INFO] [SignageApp] Loaded fallback playlist with 3 items
|
||||||
|
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
2025-08-06 02:14:39 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 3840x2160, Mode: fit, Offset: (192, 0))
|
||||||
|
[INFO] [SignageApp] Starting Simple Tkinter Media Player
|
||||||
|
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||||
|
2025-08-06 02:15:03 - STARTED: wp2782770-1846651530.jpg
|
||||||
|
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 3840x2160, Mode: fit, Offset: (192, 0))
|
||||||
|
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||||
|
2025-08-06 02:15:23 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||||
|
[INFO] [SignageApp] Video dimensions: 1280x720, Screen dimensions: 3840x2160
|
||||||
|
[INFO] [SignageApp] Media paused
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
2025-08-06 02:17:55 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||||
|
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 3840x2160, Mode: fit, Offset: (192, 0))
|
||||||
|
[INFO] [SignageApp] Application exit requested
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_local_playlist function.
|
||||||
|
[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': '1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'url': 'static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'duration': 20}, {'file_name': 'wp2782770-1846651530.jpg', 'url': 'static/resurse/wp2782770-1846651530.jpg', 'duration': 15}, {'file_name': 'SampleVideo_1280x720_1mb.mp4', 'url': 'static/resurse/SampleVideo_1280x720_1mb.mp4', 'duration': 5}], 'version': 5}
|
||||||
|
[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully.
|
||||||
|
[INFO] [SignageApp] Found fallback playlist with 3 items
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Initializing with settings: server=digi-signage.moto-adv.com, host=tv-terasa, port=8880
|
||||||
|
[INFO] [SignageApp] Attempting to connect to server...
|
||||||
|
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||||
|
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||||
|
[WARNING] [SignageApp] Server returned empty playlist, falling back to local playlist
|
||||||
|
[INFO] [SignageApp] Loaded fallback playlist with 3 items
|
||||||
|
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
2025-08-06 02:20:20 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||||
|
[INFO] [SignageApp] Starting Simple Tkinter Media Player
|
||||||
|
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||||
|
2025-08-06 02:20:40 - STARTED: wp2782770-1846651530.jpg
|
||||||
|
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||||
|
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||||
|
2025-08-06 02:20:57 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||||
|
[INFO] [SignageApp] Video dimensions: 1280x720, Screen dimensions: 1920x1080
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/signage-player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
2025-08-06 02:21:44 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||||
|
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||||
|
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||||
|
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||||
|
[INFO] [SignageApp] Application exit requested
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
tkinter_app/src/__pycache__/virtual_keyboard.cpython-311.pyc
Normal file
BIN
tkinter_app/src/__pycache__/virtual_keyboard.cpython-311.pyc
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
360
tkinter_app/src/virtual_keyboard.py
Normal file
360
tkinter_app/src/virtual_keyboard.py
Normal file
@@ -0,0 +1,360 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Virtual Keyboard Component for Touch Displays
|
||||||
|
Provides an on-screen keyboard for touch-friendly input
|
||||||
|
"""
|
||||||
|
import tkinter as tk
|
||||||
|
from tkinter import ttk
|
||||||
|
|
||||||
|
class VirtualKeyboard:
|
||||||
|
def __init__(self, parent, target_entry=None, dark_theme=True):
|
||||||
|
self.parent = parent
|
||||||
|
self.target_entry = target_entry
|
||||||
|
self.dark_theme = dark_theme
|
||||||
|
self.keyboard_window = None
|
||||||
|
self.caps_lock = False
|
||||||
|
self.shift_pressed = False
|
||||||
|
|
||||||
|
# Define color schemes
|
||||||
|
if dark_theme:
|
||||||
|
self.colors = {
|
||||||
|
'bg_primary': '#1e2124',
|
||||||
|
'bg_secondary': '#2f3136',
|
||||||
|
'bg_tertiary': '#36393f',
|
||||||
|
'accent': '#7289da',
|
||||||
|
'accent_hover': '#677bc4',
|
||||||
|
'text_primary': '#ffffff',
|
||||||
|
'text_secondary': '#b9bbbe',
|
||||||
|
'key_normal': '#4f545c',
|
||||||
|
'key_hover': '#5865f2',
|
||||||
|
'key_special': '#ed4245',
|
||||||
|
'key_function': '#57f287'
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
self.colors = {
|
||||||
|
'bg_primary': '#ffffff',
|
||||||
|
'bg_secondary': '#f8f9fa',
|
||||||
|
'bg_tertiary': '#e9ecef',
|
||||||
|
'accent': '#0d6efd',
|
||||||
|
'accent_hover': '#0b5ed7',
|
||||||
|
'text_primary': '#000000',
|
||||||
|
'text_secondary': '#6c757d',
|
||||||
|
'key_normal': '#dee2e6',
|
||||||
|
'key_hover': '#0d6efd',
|
||||||
|
'key_special': '#dc3545',
|
||||||
|
'key_function': '#198754'
|
||||||
|
}
|
||||||
|
|
||||||
|
def show_keyboard(self, entry_widget=None):
|
||||||
|
"""Show the virtual keyboard"""
|
||||||
|
if entry_widget:
|
||||||
|
self.target_entry = entry_widget
|
||||||
|
|
||||||
|
if self.keyboard_window and self.keyboard_window.winfo_exists():
|
||||||
|
self.keyboard_window.lift()
|
||||||
|
return
|
||||||
|
|
||||||
|
self.create_keyboard()
|
||||||
|
|
||||||
|
def hide_keyboard(self):
|
||||||
|
"""Hide the virtual keyboard"""
|
||||||
|
if self.keyboard_window and self.keyboard_window.winfo_exists():
|
||||||
|
self.keyboard_window.destroy()
|
||||||
|
self.keyboard_window = None
|
||||||
|
|
||||||
|
def create_keyboard(self):
|
||||||
|
"""Create the virtual keyboard window"""
|
||||||
|
self.keyboard_window = tk.Toplevel(self.parent)
|
||||||
|
self.keyboard_window.title("Virtual Keyboard")
|
||||||
|
self.keyboard_window.configure(bg=self.colors['bg_primary'])
|
||||||
|
self.keyboard_window.resizable(False, False)
|
||||||
|
|
||||||
|
# Make keyboard stay on top
|
||||||
|
self.keyboard_window.attributes('-topmost', True)
|
||||||
|
|
||||||
|
# Position keyboard at bottom of screen
|
||||||
|
self.position_keyboard()
|
||||||
|
|
||||||
|
# Create keyboard layout
|
||||||
|
self.create_keyboard_layout()
|
||||||
|
|
||||||
|
# Bind events
|
||||||
|
self.keyboard_window.protocol("WM_DELETE_WINDOW", self.hide_keyboard)
|
||||||
|
|
||||||
|
def position_keyboard(self):
|
||||||
|
"""Position keyboard at bottom center of screen"""
|
||||||
|
self.keyboard_window.update_idletasks()
|
||||||
|
|
||||||
|
# Get screen dimensions
|
||||||
|
screen_width = self.keyboard_window.winfo_screenwidth()
|
||||||
|
screen_height = self.keyboard_window.winfo_screenheight()
|
||||||
|
|
||||||
|
# Keyboard dimensions
|
||||||
|
kb_width = 800
|
||||||
|
kb_height = 300
|
||||||
|
|
||||||
|
# Position at bottom center
|
||||||
|
x = (screen_width - kb_width) // 2
|
||||||
|
y = screen_height - kb_height - 50 # 50px from bottom
|
||||||
|
|
||||||
|
self.keyboard_window.geometry(f"{kb_width}x{kb_height}+{x}+{y}")
|
||||||
|
|
||||||
|
def create_keyboard_layout(self):
|
||||||
|
"""Create the keyboard layout"""
|
||||||
|
main_frame = tk.Frame(self.keyboard_window, bg=self.colors['bg_primary'], padx=10, pady=10)
|
||||||
|
main_frame.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
# Title bar
|
||||||
|
title_frame = tk.Frame(main_frame, bg=self.colors['bg_secondary'], height=40)
|
||||||
|
title_frame.pack(fill=tk.X, pady=(0, 10))
|
||||||
|
title_frame.pack_propagate(False)
|
||||||
|
|
||||||
|
title_label = tk.Label(title_frame, text="⌨️ Virtual Keyboard",
|
||||||
|
font=('Segoe UI', 12, 'bold'),
|
||||||
|
bg=self.colors['bg_secondary'], fg=self.colors['text_primary'])
|
||||||
|
title_label.pack(side=tk.LEFT, padx=10, pady=10)
|
||||||
|
|
||||||
|
# Close button
|
||||||
|
close_btn = tk.Button(title_frame, text="✕", command=self.hide_keyboard,
|
||||||
|
bg=self.colors['key_special'], fg=self.colors['text_primary'],
|
||||||
|
font=('Segoe UI', 12, 'bold'), relief=tk.FLAT, width=3)
|
||||||
|
close_btn.pack(side=tk.RIGHT, padx=10, pady=5)
|
||||||
|
|
||||||
|
# Keyboard rows
|
||||||
|
self.create_keyboard_rows(main_frame)
|
||||||
|
|
||||||
|
def create_keyboard_rows(self, parent):
|
||||||
|
"""Create keyboard rows"""
|
||||||
|
# Define keyboard layout
|
||||||
|
rows = [
|
||||||
|
['`', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 'Backspace'],
|
||||||
|
['Tab', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\\'],
|
||||||
|
['Caps', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', "'", 'Enter'],
|
||||||
|
['Shift', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 'Shift'],
|
||||||
|
['Ctrl', 'Alt', 'Space', 'Alt', 'Ctrl']
|
||||||
|
]
|
||||||
|
|
||||||
|
# Special keys with different sizes
|
||||||
|
special_keys = {
|
||||||
|
'Backspace': 2,
|
||||||
|
'Tab': 1.5,
|
||||||
|
'Enter': 2,
|
||||||
|
'Caps': 1.8,
|
||||||
|
'Shift': 2.3,
|
||||||
|
'Ctrl': 1.2,
|
||||||
|
'Alt': 1.2,
|
||||||
|
'Space': 6
|
||||||
|
}
|
||||||
|
|
||||||
|
for row_index, row in enumerate(rows):
|
||||||
|
row_frame = tk.Frame(parent, bg=self.colors['bg_primary'])
|
||||||
|
row_frame.pack(fill=tk.X, pady=2)
|
||||||
|
|
||||||
|
for key in row:
|
||||||
|
width = special_keys.get(key, 1)
|
||||||
|
self.create_key_button(row_frame, key, width)
|
||||||
|
|
||||||
|
def create_key_button(self, parent, key, width=1):
|
||||||
|
"""Create a keyboard key button"""
|
||||||
|
# Determine key type and color
|
||||||
|
if key in ['Backspace', 'Tab', 'Enter', 'Caps', 'Shift', 'Ctrl', 'Alt']:
|
||||||
|
bg_color = self.colors['key_function']
|
||||||
|
elif key == 'Space':
|
||||||
|
bg_color = self.colors['key_normal']
|
||||||
|
else:
|
||||||
|
bg_color = self.colors['key_normal']
|
||||||
|
|
||||||
|
# Calculate button width
|
||||||
|
base_width = 4
|
||||||
|
button_width = int(base_width * width)
|
||||||
|
|
||||||
|
# Display text for special keys
|
||||||
|
display_text = {
|
||||||
|
'Backspace': '⌫',
|
||||||
|
'Tab': '⇥',
|
||||||
|
'Enter': '⏎',
|
||||||
|
'Caps': '⇪',
|
||||||
|
'Shift': '⇧',
|
||||||
|
'Ctrl': 'Ctrl',
|
||||||
|
'Alt': 'Alt',
|
||||||
|
'Space': '___'
|
||||||
|
}.get(key, key.upper() if self.caps_lock or self.shift_pressed else key)
|
||||||
|
|
||||||
|
button = tk.Button(parent, text=display_text,
|
||||||
|
command=lambda k=key: self.key_pressed(k),
|
||||||
|
bg=bg_color, fg=self.colors['text_primary'],
|
||||||
|
font=('Segoe UI', 10, 'bold'),
|
||||||
|
relief=tk.FLAT, bd=1,
|
||||||
|
width=button_width, height=2)
|
||||||
|
|
||||||
|
# Add hover effects
|
||||||
|
def on_enter(e, btn=button):
|
||||||
|
btn.configure(bg=self.colors['key_hover'])
|
||||||
|
|
||||||
|
def on_leave(e, btn=button):
|
||||||
|
btn.configure(bg=bg_color)
|
||||||
|
|
||||||
|
button.bind("<Enter>", on_enter)
|
||||||
|
button.bind("<Leave>", on_leave)
|
||||||
|
|
||||||
|
button.pack(side=tk.LEFT, padx=1, pady=1)
|
||||||
|
|
||||||
|
def key_pressed(self, key):
|
||||||
|
"""Handle key press"""
|
||||||
|
if not self.target_entry:
|
||||||
|
return
|
||||||
|
|
||||||
|
if key == 'Backspace':
|
||||||
|
current_pos = self.target_entry.index(tk.INSERT)
|
||||||
|
if current_pos > 0:
|
||||||
|
self.target_entry.delete(current_pos - 1)
|
||||||
|
|
||||||
|
elif key == 'Tab':
|
||||||
|
self.target_entry.insert(tk.INSERT, '\t')
|
||||||
|
|
||||||
|
elif key == 'Enter':
|
||||||
|
# Try to trigger any bound return event
|
||||||
|
self.target_entry.event_generate('<Return>')
|
||||||
|
|
||||||
|
elif key == 'Caps':
|
||||||
|
self.caps_lock = not self.caps_lock
|
||||||
|
self.update_key_display()
|
||||||
|
|
||||||
|
elif key == 'Shift':
|
||||||
|
self.shift_pressed = not self.shift_pressed
|
||||||
|
self.update_key_display()
|
||||||
|
|
||||||
|
elif key == 'Space':
|
||||||
|
self.target_entry.insert(tk.INSERT, ' ')
|
||||||
|
|
||||||
|
elif key in ['Ctrl', 'Alt']:
|
||||||
|
# These could be used for key combinations in the future
|
||||||
|
pass
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Regular character
|
||||||
|
char = key.upper() if self.caps_lock or self.shift_pressed else key
|
||||||
|
|
||||||
|
# Handle shifted characters
|
||||||
|
if self.shift_pressed and not self.caps_lock:
|
||||||
|
shift_map = {
|
||||||
|
'1': '!', '2': '@', '3': '#', '4': '$', '5': '%',
|
||||||
|
'6': '^', '7': '&', '8': '*', '9': '(', '0': ')',
|
||||||
|
'-': '_', '=': '+', '[': '{', ']': '}', '\\': '|',
|
||||||
|
';': ':', "'": '"', ',': '<', '.': '>', '/': '?',
|
||||||
|
'`': '~'
|
||||||
|
}
|
||||||
|
char = shift_map.get(key, char)
|
||||||
|
|
||||||
|
self.target_entry.insert(tk.INSERT, char)
|
||||||
|
|
||||||
|
# Reset shift after character input
|
||||||
|
if self.shift_pressed:
|
||||||
|
self.shift_pressed = False
|
||||||
|
self.update_key_display()
|
||||||
|
|
||||||
|
def update_key_display(self):
|
||||||
|
"""Update key display based on caps lock and shift state"""
|
||||||
|
# This would update the display of keys, but for simplicity
|
||||||
|
# we'll just recreate the keyboard when needed
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TouchOptimizedEntry(tk.Entry):
|
||||||
|
"""Entry widget optimized for touch displays with virtual keyboard"""
|
||||||
|
|
||||||
|
def __init__(self, parent, virtual_keyboard=None, **kwargs):
|
||||||
|
# Make entry larger for touch
|
||||||
|
kwargs.setdefault('font', ('Segoe UI', 12))
|
||||||
|
kwargs.setdefault('relief', tk.FLAT)
|
||||||
|
kwargs.setdefault('bd', 8)
|
||||||
|
|
||||||
|
super().__init__(parent, **kwargs)
|
||||||
|
|
||||||
|
self.virtual_keyboard = virtual_keyboard
|
||||||
|
|
||||||
|
# Bind focus events to show/hide keyboard
|
||||||
|
self.bind('<FocusIn>', self.on_focus_in)
|
||||||
|
self.bind('<Button-1>', self.on_click)
|
||||||
|
|
||||||
|
def on_focus_in(self, event):
|
||||||
|
"""Show virtual keyboard when entry gets focus"""
|
||||||
|
if self.virtual_keyboard:
|
||||||
|
self.virtual_keyboard.show_keyboard(self)
|
||||||
|
|
||||||
|
def on_click(self, event):
|
||||||
|
"""Show virtual keyboard when entry is clicked"""
|
||||||
|
if self.virtual_keyboard:
|
||||||
|
self.virtual_keyboard.show_keyboard(self)
|
||||||
|
|
||||||
|
|
||||||
|
class TouchOptimizedButton(tk.Button):
|
||||||
|
"""Button widget optimized for touch displays"""
|
||||||
|
|
||||||
|
def __init__(self, parent, **kwargs):
|
||||||
|
# Make buttons larger for touch
|
||||||
|
kwargs.setdefault('font', ('Segoe UI', 11, 'bold'))
|
||||||
|
kwargs.setdefault('relief', tk.FLAT)
|
||||||
|
kwargs.setdefault('padx', 20)
|
||||||
|
kwargs.setdefault('pady', 12)
|
||||||
|
kwargs.setdefault('cursor', 'hand2')
|
||||||
|
|
||||||
|
super().__init__(parent, **kwargs)
|
||||||
|
|
||||||
|
# Add touch feedback
|
||||||
|
self.bind('<Button-1>', self.on_touch_down)
|
||||||
|
self.bind('<ButtonRelease-1>', self.on_touch_up)
|
||||||
|
|
||||||
|
def on_touch_down(self, event):
|
||||||
|
"""Visual feedback when button is touched"""
|
||||||
|
self.configure(relief=tk.SUNKEN)
|
||||||
|
|
||||||
|
def on_touch_up(self, event):
|
||||||
|
"""Reset visual feedback when touch is released"""
|
||||||
|
self.configure(relief=tk.FLAT)
|
||||||
|
|
||||||
|
|
||||||
|
# Test the virtual keyboard
|
||||||
|
if __name__ == "__main__":
|
||||||
|
def test_virtual_keyboard():
|
||||||
|
root = tk.Tk()
|
||||||
|
root.title("Virtual Keyboard Test")
|
||||||
|
root.geometry("600x400")
|
||||||
|
root.configure(bg='#2f3136')
|
||||||
|
|
||||||
|
# Create virtual keyboard instance
|
||||||
|
vk = VirtualKeyboard(root, dark_theme=True)
|
||||||
|
|
||||||
|
# Test frame
|
||||||
|
test_frame = tk.Frame(root, bg='#2f3136', padx=20, pady=20)
|
||||||
|
test_frame.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
# Title
|
||||||
|
tk.Label(test_frame, text="🎮 Touch Display Test",
|
||||||
|
font=('Segoe UI', 16, 'bold'),
|
||||||
|
bg='#2f3136', fg='white').pack(pady=20)
|
||||||
|
|
||||||
|
# Test entries
|
||||||
|
tk.Label(test_frame, text="Click entries to show virtual keyboard:",
|
||||||
|
bg='#2f3136', fg='white', font=('Segoe UI', 12)).pack(pady=10)
|
||||||
|
|
||||||
|
entry1 = TouchOptimizedEntry(test_frame, vk, width=30, bg='#36393f',
|
||||||
|
fg='white', insertbackground='white')
|
||||||
|
entry1.pack(pady=10)
|
||||||
|
|
||||||
|
entry2 = TouchOptimizedEntry(test_frame, vk, width=30, bg='#36393f',
|
||||||
|
fg='white', insertbackground='white')
|
||||||
|
entry2.pack(pady=10)
|
||||||
|
|
||||||
|
# Test buttons
|
||||||
|
TouchOptimizedButton(test_frame, text="Show Keyboard",
|
||||||
|
command=lambda: vk.show_keyboard(entry1),
|
||||||
|
bg='#7289da', fg='white').pack(pady=10)
|
||||||
|
|
||||||
|
TouchOptimizedButton(test_frame, text="Hide Keyboard",
|
||||||
|
command=vk.hide_keyboard,
|
||||||
|
bg='#ed4245', fg='white').pack(pady=5)
|
||||||
|
|
||||||
|
root.mainloop()
|
||||||
|
|
||||||
|
test_virtual_keyboard()
|
||||||
Reference in New Issue
Block a user