226 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			226 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Python
		
	
	
	
#!/usr/bin/env python3
 | 
						|
"""
 | 
						|
Simple Text Input Widget for McRogueFace
 | 
						|
Minimal implementation focusing on core functionality
 | 
						|
"""
 | 
						|
 | 
						|
import mcrfpy
 | 
						|
import sys
 | 
						|
 | 
						|
 | 
						|
class TextInput:
 | 
						|
    """Simple text input widget"""
 | 
						|
    def __init__(self, x, y, width, label=""):
 | 
						|
        self.x = x
 | 
						|
        self.y = y
 | 
						|
        self.width = width
 | 
						|
        self.label = label
 | 
						|
        self.text = ""
 | 
						|
        self.cursor_pos = 0
 | 
						|
        self.focused = False
 | 
						|
        
 | 
						|
        # Create UI elements
 | 
						|
        self.frame = mcrfpy.Frame(self.x, self.y, self.width, 24)
 | 
						|
        self.frame.fill_color = (255, 255, 255, 255)
 | 
						|
        self.frame.outline_color = (128, 128, 128, 255)
 | 
						|
        self.frame.outline = 2
 | 
						|
        
 | 
						|
        # Label
 | 
						|
        if self.label:
 | 
						|
            self.label_caption = mcrfpy.Caption(self.label, self.x, self.y - 20)
 | 
						|
            self.label_caption.fill_color = (255, 255, 255, 255)
 | 
						|
        
 | 
						|
        # Text display
 | 
						|
        self.text_caption = mcrfpy.Caption("", self.x + 4, self.y + 4)
 | 
						|
        self.text_caption.fill_color = (0, 0, 0, 255)
 | 
						|
        
 | 
						|
        # Cursor (a simple vertical line using a frame)
 | 
						|
        self.cursor = mcrfpy.Frame(self.x + 4, self.y + 4, 2, 16)
 | 
						|
        self.cursor.fill_color = (0, 0, 0, 255)
 | 
						|
        self.cursor.visible = False
 | 
						|
        
 | 
						|
        # Click handler
 | 
						|
        self.frame.click = self._on_click
 | 
						|
    
 | 
						|
    def _on_click(self, x, y, button):
 | 
						|
        """Handle clicks"""
 | 
						|
        if button == 1:  # Left click
 | 
						|
            # Request focus
 | 
						|
            global current_focus
 | 
						|
            if current_focus and current_focus != self:
 | 
						|
                current_focus.blur()
 | 
						|
            current_focus = self
 | 
						|
            self.focus()
 | 
						|
    
 | 
						|
    def focus(self):
 | 
						|
        """Give focus to this input"""
 | 
						|
        self.focused = True
 | 
						|
        self.frame.outline_color = (0, 120, 255, 255)
 | 
						|
        self.frame.outline = 3
 | 
						|
        self.cursor.visible = True
 | 
						|
        self._update_cursor()
 | 
						|
    
 | 
						|
    def blur(self):
 | 
						|
        """Remove focus"""
 | 
						|
        self.focused = False
 | 
						|
        self.frame.outline_color = (128, 128, 128, 255)
 | 
						|
        self.frame.outline = 2
 | 
						|
        self.cursor.visible = False
 | 
						|
    
 | 
						|
    def handle_key(self, key):
 | 
						|
        """Process keyboard input"""
 | 
						|
        if not self.focused:
 | 
						|
            return False
 | 
						|
        
 | 
						|
        if key == "BackSpace":
 | 
						|
            if self.cursor_pos > 0:
 | 
						|
                self.text = self.text[:self.cursor_pos-1] + self.text[self.cursor_pos:]
 | 
						|
                self.cursor_pos -= 1
 | 
						|
        elif key == "Delete":
 | 
						|
            if self.cursor_pos < len(self.text):
 | 
						|
                self.text = self.text[:self.cursor_pos] + self.text[self.cursor_pos+1:]
 | 
						|
        elif key == "Left":
 | 
						|
            self.cursor_pos = max(0, self.cursor_pos - 1)
 | 
						|
        elif key == "Right":
 | 
						|
            self.cursor_pos = min(len(self.text), self.cursor_pos + 1)
 | 
						|
        elif key == "Home":
 | 
						|
            self.cursor_pos = 0
 | 
						|
        elif key == "End":
 | 
						|
            self.cursor_pos = len(self.text)
 | 
						|
        elif len(key) == 1 and key.isprintable():
 | 
						|
            self.text = self.text[:self.cursor_pos] + key + self.text[self.cursor_pos:]
 | 
						|
            self.cursor_pos += 1
 | 
						|
        else:
 | 
						|
            return False
 | 
						|
        
 | 
						|
        self._update_display()
 | 
						|
        return True
 | 
						|
    
 | 
						|
    def _update_display(self):
 | 
						|
        """Update text display"""
 | 
						|
        self.text_caption.text = self.text
 | 
						|
        self._update_cursor()
 | 
						|
    
 | 
						|
    def _update_cursor(self):
 | 
						|
        """Update cursor position"""
 | 
						|
        if self.focused:
 | 
						|
            # Estimate character width (roughly 10 pixels per char)
 | 
						|
            self.cursor.x = self.x + 4 + (self.cursor_pos * 10)
 | 
						|
    
 | 
						|
    def add_to_scene(self, scene):
 | 
						|
        """Add all components to scene"""
 | 
						|
        scene.append(self.frame)
 | 
						|
        if hasattr(self, 'label_caption'):
 | 
						|
            scene.append(self.label_caption)
 | 
						|
        scene.append(self.text_caption)
 | 
						|
        scene.append(self.cursor)
 | 
						|
 | 
						|
 | 
						|
# Global focus tracking
 | 
						|
current_focus = None
 | 
						|
text_inputs = []
 | 
						|
 | 
						|
 | 
						|
def demo_test(timer_name):
 | 
						|
    """Run automated demo after scene loads"""
 | 
						|
    print("\n=== Text Input Widget Demo ===")
 | 
						|
    
 | 
						|
    # Test typing in first field
 | 
						|
    print("Testing first input field...")
 | 
						|
    text_inputs[0].focus()
 | 
						|
    for char in "Hello":
 | 
						|
        text_inputs[0].handle_key(char)
 | 
						|
    
 | 
						|
    print(f"First field contains: '{text_inputs[0].text}'")
 | 
						|
    
 | 
						|
    # Test second field
 | 
						|
    print("\nTesting second input field...")
 | 
						|
    text_inputs[1].focus()
 | 
						|
    for char in "World":
 | 
						|
        text_inputs[1].handle_key(char)
 | 
						|
    
 | 
						|
    print(f"Second field contains: '{text_inputs[1].text}'")
 | 
						|
    
 | 
						|
    # Test text operations
 | 
						|
    print("\nTesting cursor movement and deletion...")
 | 
						|
    text_inputs[1].handle_key("Home")
 | 
						|
    text_inputs[1].handle_key("Delete")
 | 
						|
    print(f"After delete at start: '{text_inputs[1].text}'")
 | 
						|
    
 | 
						|
    text_inputs[1].handle_key("End")
 | 
						|
    text_inputs[1].handle_key("BackSpace")
 | 
						|
    print(f"After backspace at end: '{text_inputs[1].text}'")
 | 
						|
    
 | 
						|
    print("\n=== Demo Complete! ===")
 | 
						|
    print("Text input widget is working successfully!")
 | 
						|
    print("Features demonstrated:")
 | 
						|
    print("  - Text entry")
 | 
						|
    print("  - Focus management (blue outline)")
 | 
						|
    print("  - Cursor positioning")
 | 
						|
    print("  - Delete/Backspace operations")
 | 
						|
    
 | 
						|
    sys.exit(0)
 | 
						|
 | 
						|
 | 
						|
def create_scene():
 | 
						|
    """Create the demo scene"""
 | 
						|
    global text_inputs
 | 
						|
    
 | 
						|
    mcrfpy.createScene("demo")
 | 
						|
    scene = mcrfpy.sceneUI("demo")
 | 
						|
    
 | 
						|
    # Background
 | 
						|
    bg = mcrfpy.Frame(0, 0, 800, 600)
 | 
						|
    bg.fill_color = (40, 40, 40, 255)
 | 
						|
    scene.append(bg)
 | 
						|
    
 | 
						|
    # Title
 | 
						|
    title = mcrfpy.Caption("Text Input Widget Demo", 10, 10)
 | 
						|
    title.fill_color = (255, 255, 255, 255)
 | 
						|
    scene.append(title)
 | 
						|
    
 | 
						|
    # Create input fields
 | 
						|
    input1 = TextInput(50, 100, 300, "Name:")
 | 
						|
    input1.add_to_scene(scene)
 | 
						|
    text_inputs.append(input1)
 | 
						|
    
 | 
						|
    input2 = TextInput(50, 160, 300, "Email:")
 | 
						|
    input2.add_to_scene(scene)
 | 
						|
    text_inputs.append(input2)
 | 
						|
    
 | 
						|
    input3 = TextInput(50, 220, 400, "Comment:")
 | 
						|
    input3.add_to_scene(scene)
 | 
						|
    text_inputs.append(input3)
 | 
						|
    
 | 
						|
    # Status text
 | 
						|
    status = mcrfpy.Caption("Click to focus, type to enter text", 50, 280)
 | 
						|
    status.fill_color = (200, 200, 200, 255)
 | 
						|
    scene.append(status)
 | 
						|
    
 | 
						|
    # Keyboard handler
 | 
						|
    def handle_keys(scene_name, key):
 | 
						|
        global current_focus, text_inputs
 | 
						|
        
 | 
						|
        # Tab to switch fields
 | 
						|
        if key == "Tab" and current_focus:
 | 
						|
            idx = text_inputs.index(current_focus)
 | 
						|
            next_idx = (idx + 1) % len(text_inputs)
 | 
						|
            text_inputs[next_idx]._on_click(0, 0, 1)
 | 
						|
        else:
 | 
						|
            # Pass to focused input
 | 
						|
            if current_focus:
 | 
						|
                current_focus.handle_key(key)
 | 
						|
                # Update status
 | 
						|
                texts = [inp.text for inp in text_inputs]
 | 
						|
                status.text = f"Values: {texts[0]} | {texts[1]} | {texts[2]}"
 | 
						|
    
 | 
						|
    mcrfpy.keypressScene("demo", handle_keys)
 | 
						|
    mcrfpy.setScene("demo")
 | 
						|
    
 | 
						|
    # Schedule test
 | 
						|
    mcrfpy.setTimer("test", demo_test, 500)
 | 
						|
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
    print("Starting simple text input demo...")
 | 
						|
    create_scene() |