draft tutorial revisions
This commit is contained in:
parent
838da4571d
commit
48359b5a48
70 changed files with 6216 additions and 28 deletions
120
docs/cookbook/ui/ui_health_bar_animated.py
Normal file
120
docs/cookbook/ui/ui_health_bar_animated.py
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
"""McRogueFace - Health Bar Widget (animated)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/ui_health_bar
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/ui/ui_health_bar_animated.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
import mcrfpy
|
||||
|
||||
class AnimatedHealthBar:
|
||||
"""Health bar with smooth fill animation."""
|
||||
|
||||
def __init__(self, x, y, w, h, current, maximum):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.w = w
|
||||
self.h = h
|
||||
self.current = current
|
||||
self.display_current = current # What's visually shown
|
||||
self.maximum = maximum
|
||||
self.timer_name = f"hp_anim_{id(self)}"
|
||||
|
||||
# Background
|
||||
self.background = mcrfpy.Frame(x, y, w, h)
|
||||
self.background.fill_color = mcrfpy.Color(40, 40, 40)
|
||||
self.background.outline = 2
|
||||
self.background.outline_color = mcrfpy.Color(60, 60, 60)
|
||||
|
||||
# Damage preview (shows recent damage in different color)
|
||||
self.damage_fill = mcrfpy.Frame(x + 2, y + 2, w - 4, h - 4)
|
||||
self.damage_fill.fill_color = mcrfpy.Color(180, 50, 50)
|
||||
self.damage_fill.outline = 0
|
||||
|
||||
# Main fill
|
||||
self.fill = mcrfpy.Frame(x + 2, y + 2, w - 4, h - 4)
|
||||
self.fill.fill_color = mcrfpy.Color(50, 200, 50)
|
||||
self.fill.outline = 0
|
||||
|
||||
self._update_display()
|
||||
|
||||
def _update_display(self):
|
||||
"""Update the visual fill based on display_current."""
|
||||
ratio = max(0, min(1, self.display_current / self.maximum))
|
||||
self.fill.w = (self.w - 4) * ratio
|
||||
|
||||
# Color based on ratio
|
||||
if ratio > 0.6:
|
||||
self.fill.fill_color = mcrfpy.Color(50, 200, 50)
|
||||
elif ratio > 0.3:
|
||||
self.fill.fill_color = mcrfpy.Color(230, 180, 30)
|
||||
else:
|
||||
self.fill.fill_color = mcrfpy.Color(200, 50, 50)
|
||||
|
||||
def set_health(self, new_current, animate=True):
|
||||
"""
|
||||
Set health with optional animation.
|
||||
|
||||
Args:
|
||||
new_current: New health value
|
||||
animate: Whether to animate the transition
|
||||
"""
|
||||
old_current = self.current
|
||||
self.current = max(0, min(self.maximum, new_current))
|
||||
|
||||
if not animate:
|
||||
self.display_current = self.current
|
||||
self._update_display()
|
||||
return
|
||||
|
||||
# Show damage preview immediately
|
||||
if self.current < old_current:
|
||||
damage_ratio = self.current / self.maximum
|
||||
self.damage_fill.w = (self.w - 4) * (old_current / self.maximum)
|
||||
|
||||
# Animate the fill
|
||||
self._start_animation()
|
||||
|
||||
def _start_animation(self):
|
||||
"""Start animating toward target health."""
|
||||
mcrfpy.delTimer(self.timer_name)
|
||||
|
||||
def animate_step(dt):
|
||||
# Lerp toward target
|
||||
diff = self.current - self.display_current
|
||||
if abs(diff) < 0.5:
|
||||
self.display_current = self.current
|
||||
mcrfpy.delTimer(self.timer_name)
|
||||
# Also update damage preview
|
||||
self.damage_fill.w = self.fill.w
|
||||
else:
|
||||
# Move 10% of the way each frame
|
||||
self.display_current += diff * 0.1
|
||||
|
||||
self._update_display()
|
||||
|
||||
mcrfpy.setTimer(self.timer_name, animate_step, 16)
|
||||
|
||||
def damage(self, amount):
|
||||
"""Apply damage with animation."""
|
||||
self.set_health(self.current - amount, animate=True)
|
||||
|
||||
def heal(self, amount):
|
||||
"""Apply healing with animation."""
|
||||
self.set_health(self.current + amount, animate=True)
|
||||
|
||||
def add_to_scene(self, ui):
|
||||
"""Add all frames to scene."""
|
||||
ui.append(self.background)
|
||||
ui.append(self.damage_fill)
|
||||
ui.append(self.fill)
|
||||
|
||||
|
||||
# Usage
|
||||
hp_bar = AnimatedHealthBar(50, 50, 300, 30, current=100, maximum=100)
|
||||
hp_bar.add_to_scene(ui)
|
||||
|
||||
# Damage will animate smoothly
|
||||
hp_bar.damage(40)
|
||||
43
docs/cookbook/ui/ui_health_bar_basic.py
Normal file
43
docs/cookbook/ui/ui_health_bar_basic.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
"""McRogueFace - Health Bar Widget (basic)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/ui_health_bar
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/ui/ui_health_bar_basic.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
import mcrfpy
|
||||
|
||||
mcrfpy.createScene("game")
|
||||
mcrfpy.setScene("game")
|
||||
ui = mcrfpy.sceneUI("game")
|
||||
|
||||
# Player health bar at top
|
||||
player_hp = EnhancedHealthBar(10, 10, 300, 30, 100, 100)
|
||||
player_hp.add_to_scene(ui)
|
||||
|
||||
# Enemy health bar
|
||||
enemy_hp = EnhancedHealthBar(400, 10, 200, 20, 50, 50)
|
||||
enemy_hp.add_to_scene(ui)
|
||||
|
||||
# Simulate combat
|
||||
def combat_tick(dt):
|
||||
import random
|
||||
if random.random() < 0.3:
|
||||
player_hp.damage(random.randint(5, 15))
|
||||
if random.random() < 0.4:
|
||||
enemy_hp.damage(random.randint(3, 8))
|
||||
|
||||
mcrfpy.setTimer("combat", combat_tick, 1000)
|
||||
|
||||
# Keyboard controls for testing
|
||||
def on_key(key, state):
|
||||
if state != "start":
|
||||
return
|
||||
if key == "H":
|
||||
player_hp.heal(20)
|
||||
elif key == "D":
|
||||
player_hp.damage(10)
|
||||
|
||||
mcrfpy.keypressScene(on_key)
|
||||
123
docs/cookbook/ui/ui_health_bar_enhanced.py
Normal file
123
docs/cookbook/ui/ui_health_bar_enhanced.py
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
"""McRogueFace - Health Bar Widget (enhanced)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/ui_health_bar
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/ui/ui_health_bar_enhanced.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
import mcrfpy
|
||||
|
||||
class EnhancedHealthBar:
|
||||
"""Health bar with text display, color transitions, and animations."""
|
||||
|
||||
def __init__(self, x, y, w, h, current, maximum, show_text=True):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.w = w
|
||||
self.h = h
|
||||
self.current = current
|
||||
self.maximum = maximum
|
||||
self.show_text = show_text
|
||||
|
||||
# Color thresholds (ratio -> color)
|
||||
self.colors = {
|
||||
0.6: mcrfpy.Color(50, 205, 50), # Green when > 60%
|
||||
0.3: mcrfpy.Color(255, 165, 0), # Orange when > 30%
|
||||
0.0: mcrfpy.Color(220, 20, 20), # Red when <= 30%
|
||||
}
|
||||
|
||||
# Background frame with dark fill
|
||||
self.background = mcrfpy.Frame(x, y, w, h)
|
||||
self.background.fill_color = mcrfpy.Color(30, 30, 30)
|
||||
self.background.outline = 2
|
||||
self.background.outline_color = mcrfpy.Color(100, 100, 100)
|
||||
|
||||
# Fill frame (nested inside background conceptually)
|
||||
padding = 2
|
||||
self.fill = mcrfpy.Frame(
|
||||
x + padding,
|
||||
y + padding,
|
||||
w - padding * 2,
|
||||
h - padding * 2
|
||||
)
|
||||
self.fill.outline = 0
|
||||
|
||||
# Text label
|
||||
self.label = None
|
||||
if show_text:
|
||||
self.label = mcrfpy.Caption(
|
||||
"",
|
||||
mcrfpy.default_font,
|
||||
x + w / 2 - 20,
|
||||
y + h / 2 - 8
|
||||
)
|
||||
self.label.fill_color = mcrfpy.Color(255, 255, 255)
|
||||
self.label.outline = 1
|
||||
self.label.outline_color = mcrfpy.Color(0, 0, 0)
|
||||
|
||||
self._update()
|
||||
|
||||
def _get_color_for_ratio(self, ratio):
|
||||
"""Get the appropriate color based on health ratio."""
|
||||
for threshold, color in sorted(self.colors.items(), reverse=True):
|
||||
if ratio > threshold:
|
||||
return color
|
||||
# Return the lowest threshold color if ratio is 0 or below
|
||||
return self.colors[0.0]
|
||||
|
||||
def _update(self):
|
||||
"""Update fill width, color, and text."""
|
||||
ratio = max(0, min(1, self.current / self.maximum))
|
||||
|
||||
# Update fill width (accounting for padding)
|
||||
padding = 2
|
||||
self.fill.w = (self.w - padding * 2) * ratio
|
||||
|
||||
# Update color based on ratio
|
||||
self.fill.fill_color = self._get_color_for_ratio(ratio)
|
||||
|
||||
# Update text
|
||||
if self.label:
|
||||
self.label.text = f"{int(self.current)}/{int(self.maximum)}"
|
||||
# Center the text
|
||||
text_width = len(self.label.text) * 8 # Approximate
|
||||
self.label.x = self.x + (self.w - text_width) / 2
|
||||
|
||||
def set_health(self, current, maximum=None):
|
||||
"""Update health values."""
|
||||
self.current = max(0, current)
|
||||
if maximum is not None:
|
||||
self.maximum = maximum
|
||||
self._update()
|
||||
|
||||
def damage(self, amount):
|
||||
"""Apply damage (convenience method)."""
|
||||
self.set_health(self.current - amount)
|
||||
|
||||
def heal(self, amount):
|
||||
"""Apply healing (convenience method)."""
|
||||
self.set_health(min(self.maximum, self.current + amount))
|
||||
|
||||
def add_to_scene(self, ui):
|
||||
"""Add all components to scene UI."""
|
||||
ui.append(self.background)
|
||||
ui.append(self.fill)
|
||||
if self.label:
|
||||
ui.append(self.label)
|
||||
|
||||
|
||||
# Usage
|
||||
mcrfpy.createScene("demo")
|
||||
mcrfpy.setScene("demo")
|
||||
ui = mcrfpy.sceneUI("demo")
|
||||
|
||||
# Create enhanced health bar
|
||||
hp = EnhancedHealthBar(50, 50, 250, 25, current=100, maximum=100)
|
||||
hp.add_to_scene(ui)
|
||||
|
||||
# Simulate damage
|
||||
hp.damage(30) # Now 70/100, shows green
|
||||
hp.damage(25) # Now 45/100, shows orange
|
||||
hp.damage(20) # Now 25/100, shows red
|
||||
108
docs/cookbook/ui/ui_health_bar_multi.py
Normal file
108
docs/cookbook/ui/ui_health_bar_multi.py
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
"""McRogueFace - Health Bar Widget (multi)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/ui_health_bar
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/ui/ui_health_bar_multi.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
import mcrfpy
|
||||
|
||||
class ResourceBar:
|
||||
"""Generic resource bar that can represent any stat."""
|
||||
|
||||
def __init__(self, x, y, w, h, current, maximum,
|
||||
fill_color, bg_color=None, label=""):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.w = w
|
||||
self.h = h
|
||||
self.current = current
|
||||
self.maximum = maximum
|
||||
self.label_text = label
|
||||
|
||||
if bg_color is None:
|
||||
bg_color = mcrfpy.Color(30, 30, 30)
|
||||
|
||||
# Background
|
||||
self.background = mcrfpy.Frame(x, y, w, h)
|
||||
self.background.fill_color = bg_color
|
||||
self.background.outline = 1
|
||||
self.background.outline_color = mcrfpy.Color(60, 60, 60)
|
||||
|
||||
# Fill
|
||||
self.fill = mcrfpy.Frame(x + 1, y + 1, w - 2, h - 2)
|
||||
self.fill.fill_color = fill_color
|
||||
self.fill.outline = 0
|
||||
|
||||
# Label (left side)
|
||||
self.label = mcrfpy.Caption(label, mcrfpy.default_font, x - 30, y + 2)
|
||||
self.label.fill_color = mcrfpy.Color(200, 200, 200)
|
||||
|
||||
self._update()
|
||||
|
||||
def _update(self):
|
||||
ratio = max(0, min(1, self.current / self.maximum))
|
||||
self.fill.w = (self.w - 2) * ratio
|
||||
|
||||
def set_value(self, current, maximum=None):
|
||||
self.current = max(0, current)
|
||||
if maximum:
|
||||
self.maximum = maximum
|
||||
self._update()
|
||||
|
||||
def add_to_scene(self, ui):
|
||||
if self.label_text:
|
||||
ui.append(self.label)
|
||||
ui.append(self.background)
|
||||
ui.append(self.fill)
|
||||
|
||||
|
||||
class PlayerStats:
|
||||
"""Collection of resource bars for a player."""
|
||||
|
||||
def __init__(self, x, y):
|
||||
bar_width = 200
|
||||
bar_height = 18
|
||||
spacing = 25
|
||||
|
||||
self.hp = ResourceBar(
|
||||
x, y, bar_width, bar_height,
|
||||
current=100, maximum=100,
|
||||
fill_color=mcrfpy.Color(220, 50, 50),
|
||||
label="HP"
|
||||
)
|
||||
|
||||
self.mp = ResourceBar(
|
||||
x, y + spacing, bar_width, bar_height,
|
||||
current=50, maximum=50,
|
||||
fill_color=mcrfpy.Color(50, 100, 220),
|
||||
label="MP"
|
||||
)
|
||||
|
||||
self.stamina = ResourceBar(
|
||||
x, y + spacing * 2, bar_width, bar_height,
|
||||
current=80, maximum=80,
|
||||
fill_color=mcrfpy.Color(50, 180, 50),
|
||||
label="SP"
|
||||
)
|
||||
|
||||
def add_to_scene(self, ui):
|
||||
self.hp.add_to_scene(ui)
|
||||
self.mp.add_to_scene(ui)
|
||||
self.stamina.add_to_scene(ui)
|
||||
|
||||
|
||||
# Usage
|
||||
mcrfpy.createScene("stats_demo")
|
||||
mcrfpy.setScene("stats_demo")
|
||||
ui = mcrfpy.sceneUI("stats_demo")
|
||||
|
||||
stats = PlayerStats(80, 20)
|
||||
stats.add_to_scene(ui)
|
||||
|
||||
# Update individual stats
|
||||
stats.hp.set_value(75)
|
||||
stats.mp.set_value(30)
|
||||
stats.stamina.set_value(60)
|
||||
53
docs/cookbook/ui/ui_menu_basic.py
Normal file
53
docs/cookbook/ui/ui_menu_basic.py
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
"""McRogueFace - Selection Menu Widget (basic)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/ui_menu
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/ui/ui_menu_basic.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
import mcrfpy
|
||||
|
||||
# Setup
|
||||
mcrfpy.createScene("main_menu")
|
||||
mcrfpy.setScene("main_menu")
|
||||
ui = mcrfpy.sceneUI("main_menu")
|
||||
|
||||
# Background
|
||||
bg = mcrfpy.Frame(0, 0, 1024, 768)
|
||||
bg.fill_color = mcrfpy.Color(20, 20, 35)
|
||||
ui.append(bg)
|
||||
|
||||
# Title
|
||||
title = mcrfpy.Caption("DUNGEON QUEST", mcrfpy.default_font, 350, 100)
|
||||
title.fill_color = mcrfpy.Color(255, 200, 50)
|
||||
ui.append(title)
|
||||
|
||||
# Menu
|
||||
def start_game():
|
||||
print("Starting game...")
|
||||
|
||||
def show_options():
|
||||
print("Options...")
|
||||
|
||||
menu = Menu(
|
||||
362, 250,
|
||||
["New Game", "Continue", "Options", "Quit"],
|
||||
lambda i, opt: {
|
||||
0: start_game,
|
||||
1: lambda: print("Continue..."),
|
||||
2: show_options,
|
||||
3: mcrfpy.exit
|
||||
}.get(i, lambda: None)(),
|
||||
title="Main Menu"
|
||||
)
|
||||
menu.add_to_scene(ui)
|
||||
|
||||
# Input
|
||||
def on_key(key, state):
|
||||
if state != "start":
|
||||
return
|
||||
menu.handle_key(key)
|
||||
|
||||
mcrfpy.keypressScene(on_key)
|
||||
159
docs/cookbook/ui/ui_menu_enhanced.py
Normal file
159
docs/cookbook/ui/ui_menu_enhanced.py
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
"""McRogueFace - Selection Menu Widget (enhanced)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/ui_menu
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/ui/ui_menu_enhanced.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
import mcrfpy
|
||||
|
||||
class MenuBar:
|
||||
"""Horizontal menu bar with dropdown submenus."""
|
||||
|
||||
def __init__(self, y=0, items=None):
|
||||
"""
|
||||
Create a menu bar.
|
||||
|
||||
Args:
|
||||
y: Y position (usually 0 for top)
|
||||
items: List of dicts with 'label' and 'options' keys
|
||||
"""
|
||||
self.y = y
|
||||
self.items = items or []
|
||||
self.selected_item = 0
|
||||
self.dropdown_open = False
|
||||
self.dropdown_selected = 0
|
||||
|
||||
self.item_width = 100
|
||||
self.height = 30
|
||||
|
||||
# Main bar frame
|
||||
self.bar = mcrfpy.Frame(0, y, 1024, self.height)
|
||||
self.bar.fill_color = mcrfpy.Color(50, 50, 70)
|
||||
self.bar.outline = 0
|
||||
|
||||
# Item captions
|
||||
self.item_captions = []
|
||||
for i, item in enumerate(items):
|
||||
cap = mcrfpy.Caption(
|
||||
item['label'],
|
||||
mcrfpy.default_font,
|
||||
10 + i * self.item_width,
|
||||
y + 7
|
||||
)
|
||||
cap.fill_color = mcrfpy.Color(200, 200, 200)
|
||||
self.item_captions.append(cap)
|
||||
|
||||
# Dropdown panel (hidden initially)
|
||||
self.dropdown = None
|
||||
self.dropdown_captions = []
|
||||
|
||||
def _update_highlight(self):
|
||||
"""Update visual selection on bar."""
|
||||
for i, cap in enumerate(self.item_captions):
|
||||
if i == self.selected_item and self.dropdown_open:
|
||||
cap.fill_color = mcrfpy.Color(255, 255, 100)
|
||||
else:
|
||||
cap.fill_color = mcrfpy.Color(200, 200, 200)
|
||||
|
||||
def _show_dropdown(self, ui):
|
||||
"""Show dropdown for selected item."""
|
||||
# Remove existing dropdown
|
||||
self._hide_dropdown(ui)
|
||||
|
||||
item = self.items[self.selected_item]
|
||||
options = item.get('options', [])
|
||||
|
||||
if not options:
|
||||
return
|
||||
|
||||
x = 5 + self.selected_item * self.item_width
|
||||
y = self.y + self.height
|
||||
width = 150
|
||||
height = len(options) * 25 + 10
|
||||
|
||||
self.dropdown = mcrfpy.Frame(x, y, width, height)
|
||||
self.dropdown.fill_color = mcrfpy.Color(40, 40, 60, 250)
|
||||
self.dropdown.outline = 1
|
||||
self.dropdown.outline_color = mcrfpy.Color(80, 80, 100)
|
||||
ui.append(self.dropdown)
|
||||
|
||||
self.dropdown_captions = []
|
||||
for i, opt in enumerate(options):
|
||||
cap = mcrfpy.Caption(
|
||||
opt['label'],
|
||||
mcrfpy.default_font,
|
||||
x + 10,
|
||||
y + 5 + i * 25
|
||||
)
|
||||
cap.fill_color = mcrfpy.Color(200, 200, 200)
|
||||
self.dropdown_captions.append(cap)
|
||||
ui.append(cap)
|
||||
|
||||
self.dropdown_selected = 0
|
||||
self._update_dropdown_highlight()
|
||||
|
||||
def _hide_dropdown(self, ui):
|
||||
"""Hide dropdown menu."""
|
||||
if self.dropdown:
|
||||
try:
|
||||
ui.remove(self.dropdown)
|
||||
except:
|
||||
pass
|
||||
self.dropdown = None
|
||||
|
||||
for cap in self.dropdown_captions:
|
||||
try:
|
||||
ui.remove(cap)
|
||||
except:
|
||||
pass
|
||||
self.dropdown_captions = []
|
||||
|
||||
def _update_dropdown_highlight(self):
|
||||
"""Update dropdown selection highlight."""
|
||||
for i, cap in enumerate(self.dropdown_captions):
|
||||
if i == self.dropdown_selected:
|
||||
cap.fill_color = mcrfpy.Color(255, 255, 100)
|
||||
else:
|
||||
cap.fill_color = mcrfpy.Color(200, 200, 200)
|
||||
|
||||
def add_to_scene(self, ui):
|
||||
ui.append(self.bar)
|
||||
for cap in self.item_captions:
|
||||
ui.append(cap)
|
||||
|
||||
def handle_key(self, key, ui):
|
||||
"""Handle keyboard navigation."""
|
||||
if not self.dropdown_open:
|
||||
if key == "Left":
|
||||
self.selected_item = (self.selected_item - 1) % len(self.items)
|
||||
self._update_highlight()
|
||||
elif key == "Right":
|
||||
self.selected_item = (self.selected_item + 1) % len(self.items)
|
||||
self._update_highlight()
|
||||
elif key == "Return" or key == "Down":
|
||||
self.dropdown_open = True
|
||||
self._show_dropdown(ui)
|
||||
self._update_highlight()
|
||||
else:
|
||||
if key == "Up":
|
||||
options = self.items[self.selected_item].get('options', [])
|
||||
self.dropdown_selected = (self.dropdown_selected - 1) % len(options)
|
||||
self._update_dropdown_highlight()
|
||||
elif key == "Down":
|
||||
options = self.items[self.selected_item].get('options', [])
|
||||
self.dropdown_selected = (self.dropdown_selected + 1) % len(options)
|
||||
self._update_dropdown_highlight()
|
||||
elif key == "Return":
|
||||
opt = self.items[self.selected_item]['options'][self.dropdown_selected]
|
||||
if opt.get('action'):
|
||||
opt['action']()
|
||||
self.dropdown_open = False
|
||||
self._hide_dropdown(ui)
|
||||
self._update_highlight()
|
||||
elif key == "Escape":
|
||||
self.dropdown_open = False
|
||||
self._hide_dropdown(ui)
|
||||
self._update_highlight()
|
||||
54
docs/cookbook/ui/ui_message_log_basic.py
Normal file
54
docs/cookbook/ui/ui_message_log_basic.py
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
"""McRogueFace - Message Log Widget (basic)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/ui_message_log
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/ui/ui_message_log_basic.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
import mcrfpy
|
||||
|
||||
# Initialize
|
||||
mcrfpy.createScene("game")
|
||||
mcrfpy.setScene("game")
|
||||
ui = mcrfpy.sceneUI("game")
|
||||
|
||||
# Create log at bottom of screen
|
||||
log = EnhancedMessageLog(10, 500, 700, 250, line_height=20)
|
||||
ui.append(log.frame)
|
||||
|
||||
# Simulate game events
|
||||
def simulate_combat(dt):
|
||||
import random
|
||||
events = [
|
||||
("You swing your sword!", "combat"),
|
||||
("The orc dodges!", "combat"),
|
||||
("Critical hit!", "combat"),
|
||||
("You found a potion!", "loot"),
|
||||
]
|
||||
event = random.choice(events)
|
||||
log.add(event[0], event[1])
|
||||
|
||||
# Add messages every 2 seconds for demo
|
||||
mcrfpy.setTimer("combat_sim", simulate_combat, 2000)
|
||||
|
||||
# Keyboard controls
|
||||
def on_key(key, state):
|
||||
if state != "start":
|
||||
return
|
||||
if key == "PageUp":
|
||||
log.scroll_up(3)
|
||||
elif key == "PageDown":
|
||||
log.scroll_down(3)
|
||||
elif key == "C":
|
||||
log.set_filter('combat')
|
||||
elif key == "L":
|
||||
log.set_filter('loot')
|
||||
elif key == "A":
|
||||
log.set_filter(None) # All
|
||||
|
||||
mcrfpy.keypressScene(on_key)
|
||||
|
||||
log.system("Press PageUp/PageDown to scroll")
|
||||
log.system("Press C for combat, L for loot, A for all")
|
||||
27
docs/cookbook/ui/ui_message_log_enhanced.py
Normal file
27
docs/cookbook/ui/ui_message_log_enhanced.py
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
"""McRogueFace - Message Log Widget (enhanced)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/ui_message_log
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/ui/ui_message_log_enhanced.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
def handle_keys(key, state):
|
||||
if state != "start":
|
||||
return
|
||||
|
||||
if key == "PageUp":
|
||||
log.scroll_up(5)
|
||||
elif key == "PageDown":
|
||||
log.scroll_down(5)
|
||||
|
||||
mcrfpy.keypressScene(handle_keys)
|
||||
|
||||
# Or with mouse scroll on the frame
|
||||
def on_log_scroll(x, y, button, action):
|
||||
# Note: You may need to implement scroll detection
|
||||
# based on your input system
|
||||
pass
|
||||
|
||||
log.frame.click = on_log_scroll
|
||||
69
docs/cookbook/ui/ui_modal_dialog_basic.py
Normal file
69
docs/cookbook/ui/ui_modal_dialog_basic.py
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
"""McRogueFace - Modal Dialog Widget (basic)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/ui_modal_dialog
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/ui/ui_modal_dialog_basic.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
import mcrfpy
|
||||
|
||||
# Scene setup
|
||||
mcrfpy.createScene("game")
|
||||
mcrfpy.setScene("game")
|
||||
ui = mcrfpy.sceneUI("game")
|
||||
|
||||
# Game background
|
||||
bg = mcrfpy.Frame(0, 0, 1024, 768)
|
||||
bg.fill_color = mcrfpy.Color(25, 35, 45)
|
||||
ui.append(bg)
|
||||
|
||||
title = mcrfpy.Caption("My Game", mcrfpy.default_font, 450, 50)
|
||||
title.fill_color = mcrfpy.Color(255, 255, 255)
|
||||
ui.append(title)
|
||||
|
||||
# Quit button
|
||||
quit_btn = mcrfpy.Frame(430, 400, 160, 50)
|
||||
quit_btn.fill_color = mcrfpy.Color(150, 50, 50)
|
||||
quit_btn.outline = 2
|
||||
quit_btn.outline_color = mcrfpy.Color(200, 100, 100)
|
||||
ui.append(quit_btn)
|
||||
|
||||
quit_label = mcrfpy.Caption("Quit Game", mcrfpy.default_font, 460, 415)
|
||||
quit_label.fill_color = mcrfpy.Color(255, 255, 255)
|
||||
ui.append(quit_label)
|
||||
|
||||
# Confirmation dialog
|
||||
confirm_dialog = None
|
||||
|
||||
def show_quit_confirm():
|
||||
global confirm_dialog
|
||||
|
||||
def on_response(index, label):
|
||||
if label == "Yes":
|
||||
mcrfpy.exit()
|
||||
|
||||
confirm_dialog = EnhancedDialog(
|
||||
"Quit Game?",
|
||||
"Are you sure you want to quit?\nUnsaved progress will be lost.",
|
||||
["Yes", "No"],
|
||||
DialogStyle.WARNING,
|
||||
on_response
|
||||
)
|
||||
confirm_dialog.add_to_scene(ui)
|
||||
confirm_dialog.show()
|
||||
|
||||
quit_btn.click = lambda x, y, b, a: show_quit_confirm() if a == "start" else None
|
||||
|
||||
def on_key(key, state):
|
||||
if state != "start":
|
||||
return
|
||||
|
||||
if confirm_dialog and confirm_dialog.handle_key(key):
|
||||
return
|
||||
|
||||
if key == "Escape":
|
||||
show_quit_confirm()
|
||||
|
||||
mcrfpy.keypressScene(on_key)
|
||||
78
docs/cookbook/ui/ui_modal_dialog_enhanced.py
Normal file
78
docs/cookbook/ui/ui_modal_dialog_enhanced.py
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
"""McRogueFace - Modal Dialog Widget (enhanced)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/ui_modal_dialog
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/ui/ui_modal_dialog_enhanced.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
import mcrfpy
|
||||
|
||||
class DialogManager:
|
||||
"""Manages a queue of dialogs."""
|
||||
|
||||
def __init__(self, ui):
|
||||
self.ui = ui
|
||||
self.queue = []
|
||||
self.current = None
|
||||
|
||||
def show(self, title, message, buttons=None, style=None, callback=None):
|
||||
"""
|
||||
Queue a dialog to show.
|
||||
|
||||
If no dialog is active, shows immediately.
|
||||
Otherwise, queues for later.
|
||||
"""
|
||||
dialog_data = {
|
||||
'title': title,
|
||||
'message': message,
|
||||
'buttons': buttons or ["OK"],
|
||||
'style': style or DialogStyle.INFO,
|
||||
'callback': callback
|
||||
}
|
||||
|
||||
if self.current is None:
|
||||
self._show_dialog(dialog_data)
|
||||
else:
|
||||
self.queue.append(dialog_data)
|
||||
|
||||
def _show_dialog(self, data):
|
||||
"""Actually display a dialog."""
|
||||
def on_close(index, label):
|
||||
if data['callback']:
|
||||
data['callback'](index, label)
|
||||
self._on_dialog_closed()
|
||||
|
||||
self.current = EnhancedDialog(
|
||||
data['title'],
|
||||
data['message'],
|
||||
data['buttons'],
|
||||
data['style'],
|
||||
on_close
|
||||
)
|
||||
self.current.add_to_scene(self.ui)
|
||||
self.current.show()
|
||||
|
||||
def _on_dialog_closed(self):
|
||||
"""Handle dialog close, show next if queued."""
|
||||
self.current = None
|
||||
|
||||
if self.queue:
|
||||
next_dialog = self.queue.pop(0)
|
||||
self._show_dialog(next_dialog)
|
||||
|
||||
def handle_key(self, key):
|
||||
"""Forward key events to current dialog."""
|
||||
if self.current:
|
||||
return self.current.handle_key(key)
|
||||
return False
|
||||
|
||||
|
||||
# Usage
|
||||
manager = DialogManager(ui)
|
||||
|
||||
# Queue multiple dialogs
|
||||
manager.show("First", "This is the first message")
|
||||
manager.show("Second", "This appears after closing the first")
|
||||
manager.show("Third", "And this is last", ["Done"])
|
||||
65
docs/cookbook/ui/ui_tooltip_basic.py
Normal file
65
docs/cookbook/ui/ui_tooltip_basic.py
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
"""McRogueFace - Tooltip on Hover (basic)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/ui_tooltip
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/ui/ui_tooltip_basic.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
import mcrfpy
|
||||
|
||||
mcrfpy.createScene("game")
|
||||
mcrfpy.setScene("game")
|
||||
ui = mcrfpy.sceneUI("game")
|
||||
|
||||
# Background
|
||||
bg = mcrfpy.Frame(0, 0, 1024, 768)
|
||||
bg.fill_color = mcrfpy.Color(25, 25, 35)
|
||||
ui.append(bg)
|
||||
|
||||
# Create inventory slots with tooltips
|
||||
class InventorySlot:
|
||||
def __init__(self, x, y, item_name, item_desc, tooltip_mgr):
|
||||
self.frame = mcrfpy.Frame(x, y, 50, 50)
|
||||
self.frame.fill_color = mcrfpy.Color(50, 50, 60)
|
||||
self.frame.outline = 1
|
||||
self.frame.outline_color = mcrfpy.Color(80, 80, 90)
|
||||
|
||||
self.label = mcrfpy.Caption(item_name[:3], mcrfpy.default_font, x + 10, y + 15)
|
||||
self.label.fill_color = mcrfpy.Color(200, 200, 200)
|
||||
|
||||
tooltip_mgr.register(self.frame, item_desc, title=item_name)
|
||||
|
||||
def add_to_scene(self, ui):
|
||||
ui.append(self.frame)
|
||||
ui.append(self.label)
|
||||
|
||||
# Setup tooltip manager
|
||||
tips = TooltipManager()
|
||||
tips.hover_delay = 300
|
||||
|
||||
# Create inventory
|
||||
items = [
|
||||
("Health Potion", "Restores 50 HP\nConsumable"),
|
||||
("Mana Crystal", "Restores 30 MP\nConsumable"),
|
||||
("Iron Key", "Opens iron doors\nQuest Item"),
|
||||
("Gold Ring", "Worth 100 gold\nSell to merchant"),
|
||||
]
|
||||
|
||||
slots = []
|
||||
for i, (name, desc) in enumerate(items):
|
||||
slot = InventorySlot(100 + i * 60, 100, name, desc, tips)
|
||||
slot.add_to_scene(ui)
|
||||
slots.append(slot)
|
||||
|
||||
# Add tooltip last
|
||||
tips.add_to_scene(ui)
|
||||
|
||||
# Update loop
|
||||
def update(dt):
|
||||
from mcrfpy import automation
|
||||
x, y = automation.position()
|
||||
tips.update(x, y)
|
||||
|
||||
mcrfpy.setTimer("update", update, 50)
|
||||
80
docs/cookbook/ui/ui_tooltip_multi.py
Normal file
80
docs/cookbook/ui/ui_tooltip_multi.py
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
"""McRogueFace - Tooltip on Hover (multi)
|
||||
|
||||
Documentation: https://mcrogueface.github.io/cookbook/ui_tooltip
|
||||
Repository: https://github.com/jmccardle/McRogueFace/blob/master/docs/cookbook/ui/ui_tooltip_multi.py
|
||||
|
||||
This code is extracted from the McRogueFace documentation and can be
|
||||
run directly with: ./mcrogueface path/to/this/file.py
|
||||
"""
|
||||
|
||||
import mcrfpy
|
||||
|
||||
def create_info_icon(x, y, tooltip_text, ui):
|
||||
"""
|
||||
Create an info icon that shows tooltip on hover.
|
||||
|
||||
Args:
|
||||
x, y: Position of the icon
|
||||
tooltip_text: Text to show
|
||||
ui: Scene UI to add elements to
|
||||
"""
|
||||
# Info icon (small circle with "i")
|
||||
icon = mcrfpy.Frame(x, y, 20, 20)
|
||||
icon.fill_color = mcrfpy.Color(70, 130, 180)
|
||||
icon.outline = 1
|
||||
icon.outline_color = mcrfpy.Color(100, 160, 210)
|
||||
|
||||
icon_label = mcrfpy.Caption("i", mcrfpy.default_font, x + 6, y + 2)
|
||||
icon_label.fill_color = mcrfpy.Color(255, 255, 255)
|
||||
|
||||
# Tooltip (positioned to the right of icon)
|
||||
tip_frame = mcrfpy.Frame(x + 25, y - 5, 180, 50)
|
||||
tip_frame.fill_color = mcrfpy.Color(40, 40, 55, 240)
|
||||
tip_frame.outline = 1
|
||||
tip_frame.outline_color = mcrfpy.Color(80, 80, 100)
|
||||
tip_frame.visible = False
|
||||
|
||||
tip_text = mcrfpy.Caption(tooltip_text, mcrfpy.default_font, x + 33, y + 3)
|
||||
tip_text.fill_color = mcrfpy.Color(220, 220, 220)
|
||||
tip_text.visible = False
|
||||
|
||||
# Hover behavior
|
||||
def on_icon_hover(mx, my, button, action):
|
||||
tip_frame.visible = True
|
||||
tip_text.visible = True
|
||||
|
||||
icon.click = on_icon_hover
|
||||
|
||||
# Track when to hide
|
||||
def check_hover(dt):
|
||||
from mcrfpy import automation
|
||||
mx, my = automation.position()
|
||||
if not (icon.x <= mx <= icon.x + icon.w and
|
||||
icon.y <= my <= icon.y + icon.h):
|
||||
if tip_frame.visible:
|
||||
tip_frame.visible = False
|
||||
tip_text.visible = False
|
||||
|
||||
timer_name = f"info_hover_{id(icon)}"
|
||||
mcrfpy.setTimer(timer_name, check_hover, 100)
|
||||
|
||||
# Add to scene
|
||||
ui.append(icon)
|
||||
ui.append(icon_label)
|
||||
ui.append(tip_frame)
|
||||
ui.append(tip_text)
|
||||
|
||||
return icon
|
||||
|
||||
|
||||
# Usage
|
||||
mcrfpy.createScene("info_demo")
|
||||
mcrfpy.setScene("info_demo")
|
||||
ui = mcrfpy.sceneUI("info_demo")
|
||||
|
||||
# Setting with info icon
|
||||
setting_label = mcrfpy.Caption("Difficulty:", mcrfpy.default_font, 100, 100)
|
||||
setting_label.fill_color = mcrfpy.Color(200, 200, 200)
|
||||
ui.append(setting_label)
|
||||
|
||||
create_info_icon(200, 98, "Affects enemy\nHP and damage", ui)
|
||||
Loading…
Add table
Add a link
Reference in a new issue