from pygame.locals import *
from pythonosc import osc_message_builder
from pythonosc import udp_client
pygame.key.set_repeat(400, 50) # Set initial delay to 400ms and each subsequent repeat at 50ms
# Constants for the Window
COMMENT_PROFILE_SIZE = 30
POST_BOX_SIZE = 300 # Square size for post image
COMMENT_BOX_Y = POST_BOX_Y + POST_BOX_SIZE + 20
OUTPUT_BOX_WIDTH = WINDOW_WIDTH - 100
BACKGROUND_COLOR = (0, 0, 0) # Black background
TEXT_FIELD_COLOR = (40, 40, 40) # Dark grey for fields
TEXT_COLOR = (255, 255, 255) # White text
SECONDARY_TEXT_COLOR = (160, 160, 160) # Light gray text
LABELS = ["Angel", "Hero", "Feminist", "Rebel"]
# Initialize pygame window
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption("Florence Nightingale - Living Portrait (Social Media Style)")
font = pygame.font.Font(None, 24) # Smaller font for comments
username_font = pygame.font.Font(None, 24)
timestamp_font = pygame.font.Font(None, 20)
client = udp_client.SimpleUDPClient("127.0.0.1", 9000)
# Load and create a circular profile picture
profile_image_path = r"H:/My Drive/02_Projects/46_FNG_Florence_Nightingale/01_Sketches + R&D/Images/Portrait of Florence Nightingale.jpeg"
profile_image = pygame.image.load(profile_image_path)
profile_image = pygame.transform.scale(profile_image, (PROFILE_PIC_SIZE, PROFILE_PIC_SIZE))
# Load individual images for each comment profile picture
comment_profiles_paths = [
r"H:/My Drive/02_Projects/46_FNG_Florence_Nightingale/01_Sketches + R&D/Images/Queen_Victoria.jpg",
r"H:/My Drive/02_Projects/46_FNG_Florence_Nightingale/01_Sketches + R&D/Images/William_Farr.jpg",
r"H:/My Drive/02_Projects/46_FNG_Florence_Nightingale/01_Sketches + R&D/Images/12808.jpg"
comment_profile_images = []
for path in comment_profiles_paths:
image = pygame.image.load(path)
image = pygame.transform.scale(image, (COMMENT_PROFILE_SIZE, COMMENT_PROFILE_SIZE))
comment_profile_images.append(image)
# Function to create a circular mask
def create_circular_mask(size):
mask = pygame.Surface((size, size), pygame.SRCALPHA)
pygame.draw.circle(mask, (255, 255, 255, 255), (size // 2, size // 2), size // 2)
# Apply the mask to the profile images
mask_profile = create_circular_mask(PROFILE_PIC_SIZE)
profile_image = profile_image.convert_alpha()
profile_image.blit(mask_profile, (0, 0), special_flags=pygame.BLEND_RGBA_MIN)
mask_comment = create_circular_mask(COMMENT_PROFILE_SIZE)
for i in range(len(comment_profile_images)):
comment_profile_images[i] = comment_profile_images[i].convert_alpha()
comment_profile_images[i].blit(mask_comment, (0, 0), special_flags=pygame.BLEND_RGBA_MIN)
post_image_path = r"H:/My Drive/02_Projects/46_FNG_Florence_Nightingale/01_Sketches + R&D/Images/Portrait of Florence Nightingale.jpeg"
post_image = pygame.image.load(post_image_path)
post_image = pygame.transform.scale(post_image, (POST_BOX_SIZE, POST_BOX_SIZE))
input_text = "" # Stores the user input
output_values = [0] * 4 # Array to store the randomized outputs
cursor_position = 0 # Position of cursor within input_text
text_offset = 10 # X offset for text start inside input box
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
placeholder_comments = ["Love Love Love!", "Not sure about Florence tbh?", "What a rebel!"]
# Load the profile picture for the input text box separately (adjust the path)
input_profile_image_path = 'H:/My Drive/02_Projects/46_FNG_Florence_Nightingale/01_Sketches + R&D/Images/avatar.jpg'
input_profile_image = pygame.image.load(input_profile_image_path)
input_profile_image = pygame.transform.scale(input_profile_image, (COMMENT_PROFILE_SIZE, COMMENT_PROFILE_SIZE))
# Define special word distributions
special_word_distributions = {
"angel": [50, 20, 5, 25],
"feminist": [5, 5, 80, 10],
"rebel": [25, 25, 10, 40]
# Clear window background
screen.fill(BACKGROUND_COLOR)
screen.blit(profile_image, (POST_BOX_X, USERNAME_Y))
username_surface = username_font.render("@therealFlorenceNightingale", True, TEXT_COLOR)
username_rect = username_surface.get_rect(topleft=(POST_BOX_X + PROFILE_PIC_SIZE + 10, USERNAME_Y))
screen.blit(username_surface, username_rect)
timestamp_surface = timestamp_font.render(timestamp, True, SECONDARY_TEXT_COLOR)
timestamp_rect = timestamp_surface.get_rect(topleft=(POST_BOX_X + PROFILE_PIC_SIZE + 10, TIMESTAMP_Y))
screen.blit(timestamp_surface, timestamp_rect)
screen.blit(post_image, (POST_BOX_X, POST_BOX_Y))
# Comment section (Input Field as First Comment)
comment_box_x = POST_BOX_X
comment_box_width = POST_BOX_SIZE
input_field_y = COMMENT_BOX_Y
pygame.draw.rect(screen, TEXT_FIELD_COLOR, (comment_box_x, input_field_y, comment_box_width, 40),
text = input_text[:cursor_position] + ("|" if show_cursor else "") + input_text[cursor_position:]
text_surface = font.render(text, True, TEXT_COLOR)
screen.blit(text_surface, (comment_box_x + COMMENT_PROFILE_SIZE + text_offset, input_field_y + 10))
screen.blit(input_profile_image, (comment_box_x, input_field_y + 5)) # Using the dedicated profile picture for input
# Placeholder comments below the input field
for i, comment in enumerate(placeholder_comments):
box_y = input_field_y + 50 + i * 50
pygame.draw.rect(screen, TEXT_FIELD_COLOR, (comment_box_x + COMMENT_PROFILE_SIZE + 10, box_y, comment_box_width - COMMENT_PROFILE_SIZE - 10, 40),
comment_surface = font.render(comment, True, SECONDARY_TEXT_COLOR)
screen.blit(comment_surface, (comment_box_x + COMMENT_PROFILE_SIZE + 20, box_y + 10))
if i < len(comment_profile_images): # Ensure there's an image available for each comment
screen.blit(comment_profile_images[i], (comment_box_x, box_y + 5)) # Use correct indexing to avoid out-of-range error
# Output Values Box (Positioned Below Comments)
output_box_y = input_field_y + 50 + len(placeholder_comments) * 50 + 10
pygame.draw.rect(screen, TEXT_FIELD_COLOR, (comment_box_x, output_box_y, OUTPUT_BOX_WIDTH, OUTPUT_BOX_HEIGHT),
for i, label in enumerate(LABELS):
label_surface = font.render(f"{label}: {output_values[i]}", True, TEXT_COLOR)
label_rect = label_surface.get_rect(topleft=(comment_box_x + 20, output_box_y + 20 + i * 30))
screen.blit(label_surface, label_rect)
clock = pygame.time.Clock()
for event in pygame.event.get():
elif event.type == KEYDOWN:
if event.key == K_RETURN:
matched_special_word = None
for word in special_word_distributions:
if word in input_text.lower():
matched_special_word = word
combined_input = input_text.lower() # Get the input text
uuid_part = str(uuid.uuid4()) # Generate UUID
combined_input_with_uuid = combined_input + uuid_part # Combine input text and UUID
base_seed = hash(combined_input_with_uuid) # Hash the combined input to generate a seed
random.seed(base_seed) # Seed the random number generator
print("Combined Input:", combined_input)
print("Combined Input with UUID:", combined_input_with_uuid)
print("Seed:", base_seed) # Print out the seed for debugging
if matched_special_word: # Check if any special word is matched
output_values = special_word_distributions[matched_special_word]
print("Using Special Word Distribution:", matched_special_word)
# Generate random values directly without using seed
output_values = [random.randint(1, 100) for _ in range(4)]
print("Output values:", output_values) # Print out the output values for debugging
osc_msg = osc_message_builder.OscMessageBuilder(address="/randomValues")
for value in output_values:
client.send(osc_msg.build())
# Update the timestamp with the current time
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
elif event.key == K_BACKSPACE:
if cursor_position > 0 and input_text:
input_text = input_text[:cursor_position - 1] + input_text[cursor_position:]
elif event.key == K_DELETE:
if cursor_position < len(input_text):
input_text = input_text[:cursor_position] + input_text[cursor_position + 1:]
elif event.key == K_LEFT:
elif event.key == K_RIGHT:
if cursor_position < len(input_text):
elif 32 <= event.key <= 126:
input_text = input_text[:cursor_position] + event.unicode + input_text[cursor_position:]
if cursor_timer >= CURSOR_BLINK_TIME:
show_cursor = not show_cursor