الجمعة، 11 أبريل 2025
import pygame
import json
import os
import sys
from pygame.locals import *
import math
class ScratchLikeApp:
def __init__(self):
pygame.init()
pygame.mixer.init() # تهيئة نظام الصوت
self.width, self.height = 1280, 720
self.screen = pygame.display.set_mode((self.width, self.height))
pygame.display.set_caption("Scratch Like - برمجة تفاعلية متطورة")
# تحميل الخطوط
try:
self.font = pygame.font.Font(None, 24)
self.title_font = pygame.font.Font(None, 28)
self.header_font = pygame.font.Font(None, 32)
except:
self.font = pygame.font.SysFont('Arial', 16)
self.title_font = pygame.font.SysFont('Arial', 20)
self.header_font = pygame.font.SysFont('Arial', 24)
# نظام الألوان المحسن
self.colors = {
'primary': (74, 111, 165), # أزرق رئيسي
'secondary': (255, 159, 28), # برتقالي
'background': (248, 249, 250), # خلفية فاتحة
'panel': (233, 236, 239),
'text': (33, 37, 41),
'highlight': (255, 209, 102), # أصفر للتمييز
'success': (40, 167, 69),
'danger': (220, 53, 69),
'block_colors': {
'motion': (76, 201, 240), # أزرق فاتح
'looks': (247, 37, 133), # وردي
'sound': (114, 9, 183), # بنفسجي
'control': (58, 134, 255), # أزرق
'event': (46, 196, 182), # تركواز
'variables': (108, 117, 125) # رمادي
}
}
# تحميل المؤثرات الصوتية
self.sounds = {
'click': self.load_sound('click.wav'),
'success': self.load_sound('success.wav'),
'error': self.load_sound('error.wav'),
'connect': self.load_sound('connect.wav')
}
# الكتل المتاحة (مصنفة)
self.blocks = {
'الأحداث': [
{'type': 'on_start', 'name': 'عند البدء', 'inputs': [], 'color': 'event'},
{'type': 'on_click', 'name': 'عند النقر', 'inputs': [], 'color': 'event'},
{'type': 'on_key', 'name': 'عند الضغط على مفتاح', 'inputs': [
{'type': 'dropdown', 'options': ['مسافة', 'أعلى', 'أسفل', 'يسار', 'يمين'], 'value': 'مسافة'}
], 'color': 'event'}
],
'الحركة': [
{'type': 'move', 'name': 'تحرك', 'inputs': [
{'type': 'number', 'default': 10, 'value': 10}
], 'color': 'motion'},
{'type': 'turn', 'name': 'استدر', 'inputs': [
{'type': 'number', 'default': 15, 'value': 15}
], 'color': 'motion'},
{'type': 'go_to', 'name': 'انتقل إلى', 'inputs': [
{'type': 'dropdown', 'options': ['الماوس', 'المركز', 'عشوائي'], 'value': 'الماوس'}
], 'color': 'motion'}
],
'المظهر': [
{'type': 'say', 'name': 'قل', 'inputs': [
{'type': 'text', 'default': 'مرحبا!', 'value': 'مرحبا!'}
], 'color': 'looks'},
{'type': 'change_size', 'name': 'غير الحجم إلى', 'inputs': [
{'type': 'number', 'default': 100, 'value': 100}
], 'color': 'looks'},
{'type': 'show', 'name': 'أظهر', 'inputs': [], 'color': 'looks'},
{'type': 'hide', 'name': 'أخف', 'inputs': [], 'color': 'looks'}
],
'الصوت': [
{'type': 'play_sound', 'name': 'شغل الصوت', 'inputs': [
{'type': 'dropdown', 'options': ['بونج', 'نقر', 'نجاح'], 'value': 'نقر'}
], 'color': 'sound'},
{'type': 'stop_sounds', 'name': 'أوقف كل الأصوات', 'inputs': [], 'color': 'sound'},
{'type': 'change_volume', 'name': 'غير مستوى الصوت', 'inputs': [
{'type': 'number', 'default': 50, 'value': 50}
], 'color': 'sound'}
],
'التحكم': [
{'type': 'repeat', 'name': 'كرر', 'inputs': [
{'type': 'number', 'default': 10, 'value': 10}
], 'color': 'control'},
{'type': 'wait', 'name': 'انتظر', 'inputs': [
{'type': 'number', 'default': 1, 'value': 1}
], 'color': 'control'},
{'type': 'if', 'name': 'إذا', 'inputs': [
{'type': 'condition', 'default': 'True', 'value': 'True'}
], 'color': 'control'}
],
'المتغيرات': [
{'type': 'set_var', 'name': 'اجعل', 'inputs': [
{'type': 'text', 'default': 'متغير', 'value': 'متغير'},
{'type': 'number', 'default': 0, 'value': 0}
], 'color': 'variables'}
]
}
# حالة التطبيق
self.project = {
'name': 'مشروع جديد',
'sprites': [
{
'name': 'الكائن 1',
'x': 100,
'y': 100,
'size': 100,
'direction': 90,
'visible': True,
'costumes': [],
'current_costume': 0,
'sounds': []
}
],
'scripts': [[]],
'variables': {},
'current_sprite': 0,
'volume': 70
}
# تحميل الأصوات الافتراضية
self.load_default_sounds()
# واجهة المستخدم
self.tabs = [
{'name': 'البرمجة', 'icon': '🧩', 'active': True},
{'name': 'الكائنات', 'icon': '👾', 'active': False},
{'name': 'الأصوات', 'icon': '🎵', 'active': False},
{'name': 'الإعدادات', 'icon': '⚙️', 'active': False}
]
self.current_tab = 0
self.dragging = False
self.current_block = None
self.drag_offset = (0, 0)
self.hover_button = None
self.hover_tab = None
self.hover_sprite = None
self.editing_input = None
self.output = "مرحباً! ابدأ بسحب الكتل إلى مساحة العمل"
self.running = False
self.show_tutorial = True
# إنشاء مجلدات المشاريع إذا لم تكن موجودة
if not os.path.exists('projects'):
os.makedirs('projects')
if not os.path.exists('projects/sounds'):
os.makedirs('projects/sounds')
# تحميل أي موارد إضافية
self.load_resources()
# تحميل الأصوات للكائنات
for sprite in self.project['sprites']:
self.load_sprite_sounds(sprite)
def load_sound(self, filename):
"""تحميل صوت من ملف أو استخدام صوت افتراضي إذا لم يوجد"""
try:
if os.path.exists(f'projects/sounds/{filename}'):
return pygame.mixer.Sound(f'projects/sounds/{filename}')
else:
# إنشاء صوت افتراضي (نغمة بسيطة)
sound = pygame.mixer.Sound(buffer=bytearray([128 + int(127 * math.sin(i * 0.1)) for i in range(44100)]))
return sound
except:
return None
def load_default_sounds(self):
"""إنشاء أصوات افتراضية إذا لم تكن موجودة"""
default_sounds = {
'click.wav': (440, 0.1),
'success.wav': (880, 0.3),
'error.wav': (220, 0.5),
'connect.wav': (660, 0.2)
}
for filename, (freq, duration) in default_sounds.items():
if not os.path.exists(f'projects/sounds/{filename}'):
try:
# إنشاء نغمة بسيطة وحفظها
sample_rate = 44100
samples = int(sample_rate * duration)
buf = bytearray(samples)
for i in range(samples):
buf[i] = 128 + int(127 * math.sin(2 * math.pi * freq * i / sample_rate))
sound = pygame.mixer.Sound(buffer=buf)
sound.set_volume(0.5)
pygame.mixer.Sound.save(sound, f'projects/sounds/{filename}')
except:
continue
def load_sprite_sounds(self, sprite):
"""تحميل الأصوات المرتبطة بالكائن"""
sprite['sounds'] = []
sprite_sounds_dir = f'projects/sounds/{sprite["name"]}'
if os.path.exists(sprite_sounds_dir):
for file in os.listdir(sprite_sounds_dir):
if file.lower().endswith(('.wav', '.ogg', '.mp3')):
try:
sound = pygame.mixer.Sound(f'{sprite_sounds_dir}/{file}')
sprite['sounds'].append({
'name': os.path.splitext(file)[0],
'sound': sound,
'path': f'{sprite_sounds_dir}/{file}'
})
except:
continue
# إضافة أصوات افتراضية إذا لم يكن هناك أصوات
if not sprite['sounds']:
for name in ['نغمة 1', 'نغمة 2']:
sprite['sounds'].append({
'name': name,
'sound': self.load_sound('click.wav'),
'path': None
})
def load_resources(self):
"""تحميل الموارد الإضافية"""
try:
# تحميل أي صور موجودة للكائنات
for sprite in self.project['sprites']:
sprite['costumes'] = []
sprite_dir = f'projects/{sprite["name"]}'
if os.path.exists(sprite_dir):
for file in os.listdir(sprite_dir):
if file.lower().endswith(('.png', '.jpg', '.jpeg', '.gif')):
try:
img = pygame.image.load(f'{sprite_dir}/{file}')
img = pygame.transform.scale(img, (100, 100))
sprite['costumes'].append({
'name': os.path.splitext(file)[0],
'image': img,
'path': f'{sprite_dir}/{file}'
})
except:
continue
# إذا لم يكن هناك مظاهر، نضيف مظهر افتراضي
if not sprite['costumes']:
default_surface = pygame.Surface((100, 100), pygame.SRCALPHA)
pygame.draw.circle(default_surface, (255, 100, 100), (50, 50), 45)
sprite['costumes'].append({
'name': 'مظهر افتراضي',
'image': default_surface,
'path': None
})
except Exception as e:
print(f"خطأ في تحميل الموارد: {e}")
def draw_block(self, block, x, y, width=200, is_template=False, is_event=False):
"""رسم كتلة برمجية مع التصميم المحسن"""
color = self.colors['block_colors'][block.get('color', 'control')]
# إذا كانت كتلة حدث رئيسية
if is_event:
height = 60
pygame.draw.rect(self.screen, color, (x, y, width, height), border_radius=12)
pygame.draw.rect(self.screen, self.darken_color(color), (x, y, width, height), 2, border_radius=12)
else:
height = 50
pygame.draw.rect(self.screen, color, (x, y, width, height), border_radius=10)
pygame.draw.rect(self.screen, self.darken_color(color), (x, y, width, height), 2, border_radius=10)
# تأثير ظل للكتل غير القوالب
if not is_template:
shadow = pygame.Surface((width, height), pygame.SRCALPHA)
shadow.fill((0, 0, 0, 30))
self.screen.blit(shadow, (x+3, y+3))
# عرض اسم الكتلة
text = self.title_font.render(block['name'], True, (255, 255, 255))
self.screen.blit(text, (x + 15, y + (20 if is_event else 15)))
# عرض المدخلات إذا كانت موجودة
if 'inputs' in block and not is_template:
input_y = y + 40 if is_event else y + 30
for i, inp in enumerate(block['inputs']):
if inp['type'] == 'number':
input_rect = pygame.Rect(x + 120, input_y + i*25, 60, 25)
pygame.draw.rect(self.screen, (255, 255, 255), input_rect, border_radius=5)
pygame.draw.rect(self.screen, (0, 0, 0), input_rect, 1, border_radius=5)
val = str(inp.get('value', inp.get('default', '')))
input_text = self.font.render(val, True, (0, 0, 0))
self.screen.blit(input_text, (x + 125, input_y + i*25 + 3))
elif inp['type'] == 'text':
input_rect = pygame.Rect(x + 120, input_y + i*25, 120, 25)
pygame.draw.rect(self.screen, (255, 255, 255), input_rect, border_radius=5)
pygame.draw.rect(self.screen, (0, 0, 0), input_rect, 1, border_radius=5)
val = str(inp.get('value', inp.get('default', ''))[:15]
input_text = self.font.render(val, True, (0, 0, 0))
self.screen.blit(input_text, (x + 125, input_y + i*25 + 3))
elif inp['type'] == 'dropdown':
input_rect = pygame.Rect(x + 120, input_y + i*25, 100, 25)
pygame.draw.rect(self.screen, (255, 255, 255), input_rect, border_radius=5)
pygame.draw.rect(self.screen, (0, 0, 0), input_rect, 1, border_radius=5)
selected = inp.get('value', inp.get('options', [''])[0])
input_text = self.font.render(selected, True, (0, 0, 0))
self.screen.blit(input_text, (x + 125, input_y + i*25 + 3))
return pygame.Rect(x, y, width, height)
def darken_color(self, color, factor=0.7):
"""تغميق اللون لعمل حدود أو تأثيرات"""
return tuple(max(0, int(c * factor)) for c in color)
def draw_palette(self):
"""رسم لوحة الكتل مع التصميم الجديد"""
# خلفية اللوحة
pygame.draw.rect(self.screen, self.colors['panel'], (10, 50, 250, self.height-160), border_radius=15)
pygame.draw.rect(self.screen, self.darken_color(self.colors['panel']), (10, 50, 250, self.height-160), 2, border_radius=15)
# شريط عنوان اللوحة
pygame.draw.rect(self.screen, self.colors['primary'], (10, 50, 250, 40), border_top_left_radius=15, border_top_right_radius=15)
title = self.header_font.render("الكتل البرمجية", True, (255, 255, 255))
self.screen.blit(title, (20, 60))
# عرض الكتل المصنفة
y_offset = 100
for category, blocks in self.blocks.items():
# عنوان الفئة
pygame.draw.rect(self.screen, self.lighten_color(self.colors['panel']), (15, y_offset-25, 240, 30), border_radius=5)
cat_text = self.title_font.render(category, True, self.colors['text'])
self.screen.blit(cat_text, (20, y_offset-20))
# كتل الفئة
for block in blocks:
block_rect = self.draw_block(block, 20, y_offset, 220, True)
y_offset += 60
y_offset += 20 # مسافة بين الفئات
def lighten_color(self, color, factor=0.1):
"""تفتيح اللون لعناوين الفئات"""
return tuple(min(255, int(c + (255 - c) * factor)) for c in color)
def draw_workspace(self):
"""رسم مساحة العمل مع التصميم المحسن"""
# خلفية مساحة العمل
pygame.draw.rect(self.screen, (255, 255, 255), (270, 50, self.width-280, self.height-120), border_radius=15)
pygame.draw.rect(self.screen, self.colors['primary'], (270, 50, self.width-280, self.height-120), 2, border_radius=15)
# المسرح المصغر
stage_rect = pygame.Rect(self.width-300, 70, 260, 180)
pygame.draw.rect(self.screen, (240, 240, 240), stage_rect, border_radius=10)
pygame.draw.rect(self.screen, (200, 200, 200), stage_rect, 2, border_radius=10)
# عرض الكائنات على المسرح
for sprite in self.project['sprites']:
if sprite['visible'] and sprite['costumes']:
costume = sprite['costumes'][sprite['current_costume']]
scale = min(50 / max(costume['image'].get_width(), 1),
50 / max(costume['image'].get_height(), 1))
scaled_width = int(costume['image'].get_width() * scale)
scaled_height = int(costume['image'].get_height() * scale)
scaled_img = pygame.transform.scale(costume['image'], (scaled_width, scaled_height))
# حساب الموقع على المسرح المصغر
stage_x = self.width-300 + 130 + (sprite['x'] - 240) / 5
stage_y = 70 + 90 + (sprite['y'] - 180) / 5
# تدوير الصورة
rotated_img = pygame.transform.rotate(scaled_img, -sprite['direction'] + 90)
rect = rotated_img.get_rect(center=(stage_x, stage_y))
self.screen.blit(rotated_img, rect.topleft)
# عرض الكتل في مساحة العمل
y_offset = 70
for script in self.project['scripts'][self.current_tab]:
if script['event']:
event_rect = self.draw_block(script['event'], 290, y_offset, 250, False, True)
y_offset += 70
for block in script['blocks']:
block_rect = self.draw_block(block, 320, y_offset, 220)
y_offset += 60
# تأثيرات السحب
if self.dragging and self.current_block:
self.draw_dragging_block()
def draw_dragging_block(self):
"""رسم الكتلة أثناء سحبها بتأثيرات خاصة"""
mouse_pos = pygame.mouse.get_pos()
width = 250 if self.current_block['type'].startswith('on_') else 220
# تأثير شفافية
block_surface = pygame.Surface((width, 60 if self.current_block['type'].startswith('on_') else 50), pygame.SRCALPHA)
color = self.colors['block_colors'][self.current_block.get('color', 'control')]
block_surface.fill((*color, 200))
# تأثير ظل
shadow = pygame.Surface((width + 5, (60 if self.current_block['type'].startswith('on_') else 50) + 5), pygame.SRCALPHA)
shadow.fill((0, 0, 0, 50))
self.screen.blit(shadow, (mouse_pos[0] - self.drag_offset[0] + 3, mouse_pos[1] - self.drag_offset[1] + 3))
# رسم الكتلة
self.screen.blit(block_surface, (mouse_pos[0] - self.drag_offset[0], mouse_pos[1] - self.drag_offset[1]))
# رسم النص
text = self.title_font.render(self.current_block['name'], True, (255, 255, 255))
self.screen.blit(text, (mouse_pos[0] - self.drag_offset[0] + 15,
mouse_pos[1] - self.drag_offset[1] + (20 if self.current_block['type'].startswith('on_') else 15)))
def draw_tabs(self):
"""رسم تبويبات الواجهة بتصميم حديث"""
for i, tab in enumerate(self.tabs):
tab_rect = pygame.Rect(270 + i*150, 10, 140, 40)
color = self.colors['primary'] if i == self.current_tab else self.lighten_color(self.colors['panel'], 0.3)
hover_color = self.lighten_color(color, 0.2)
current_color = hover_color if self.hover_tab == i else color
pygame.draw.rect(self.screen, current_color, tab_rect, border_radius=20)
pygame.draw.rect(self.screen, self.darken_color(current_color), tab_rect, 2, border_radius=20)
# أيقونة التبويب
icon = self.font.render(tab['icon'], True, (255, 255, 255))
self.screen.blit(icon, (270 + i*150 + 15, 20))
# اسم التبويب
tab_text = self.title_font.render(tab['name'], True, (255, 255, 255))
self.screen.blit(tab_text, (270 + i*150 + 45, 20))
# زر إضافة تبويب جديد
add_rect = pygame.Rect(270 + len(self.tabs)*150 + 10, 15, 30, 30)
pygame.draw.rect(self.screen, self.colors['secondary'], add_rect, border_radius=15)
add_text = self.title_font.render("+", True, (255, 255, 255))
self.screen.blit(add_text, (270 + len(self.tabs)*150 + 20, 20))
return add_rect
def draw_toolbar(self):
"""رسم شريط الأدوات العائم"""
toolbar_rect = pygame.Rect(self.width - 80, self.height - 80, 60, 60)
pygame.draw.circle(self.screen, self.colors['primary'], (self.width - 50, self.height - 50), 30)
pygame.draw.circle(self.screen, self.darken_color(self.colors['primary']), (self.width - 50, self.height - 50), 30, 2)
# أيقونة القائمة
menu_icon = [
(self.width - 60, self.height - 55, 20, 5),
(self.width - 60, self.height - 50, 20, 5),
(self.width - 60, self.height - 45, 20, 5)
]
for x, y, w, h in menu_icon:
pygame.draw.rect(self.screen, (255, 255, 255), (x, y, w, h), border_radius=2)
# القائمة الموسعة عند النقر
if self.hover_button == 'toolbar':
tools = [
('💾', 'حفظ', (self.width - 180, self.height - 120)),
('▶️', 'تشغيل', (self.width - 180, self.height - 70)),
('🔄', 'إعادة تعيين', (self.width - 120, self.height - 120)),
('🎨', 'المظاهر', (self.width - 120, self.height - 70)),
('🔊', 'الأصوات', (self.width - 60, self.height - 120))
]
for icon, text, pos in tools:
pygame.draw.rect(self.screen, self.colors['secondary'], (*pos, 50, 40), border_radius=10)
icon_surf = self.font.render(icon, True, (255, 255, 255))
self.screen.blit(icon_surf, (pos[0] + 15, pos[1] + 5))
text_surf = self.font.render(text, True, (255, 255, 255))
self.screen.blit(text_surf, (pos[0] + 5, pos[1] + 25))
return toolbar_rect
def draw_output(self):
"""رسم منطقة الإخراج مع تصميم حديث"""
output_rect = pygame.Rect(270, self.height-60, self.width-280, 50)
pygame.draw.rect(self.screen, (255, 255, 255), output_rect, border_radius=10)
pygame.draw.rect(self.screen, self.colors['primary'], output_rect, 2, border_radius=10)
# نص الإخراج مع تقطيع إذا كان طويلاً
output_text = self.output[:100] + "..." if len(self.output) > 100 else self.output
text_surf = self.font.render(output_text, True, (0, 0, 0))
self.screen.blit(text_surf, (280, self.height-50))
# أيقونة حالة التشغيل
status_color = self.colors['success'] if self.running else self.colors['danger']
pygame.draw.circle(self.screen, status_color, (self.width-40, self.height-35), 8)
def draw_sprite_panel(self):
"""رسم لوحة الكائنات المحسنة"""
panel_rect = pygame.Rect(10, self.height-100, 250, 90)
pygame.draw.rect(self.screen, self.colors['panel'], panel_rect, border_radius=15)
pygame.draw.rect(self.screen, self.darken_color(self.colors['panel']), panel_rect, 2, border_radius=15)
# عنوان اللوحة
title = self.title_font.render("الكائنات", True, self.colors['text'])
self.screen.blit(title, (20, self.height-90))
# قائمة الكائنات
x_offset = 20
for i, sprite in enumerate(self.project['sprites']):
sprite_rect = pygame.Rect(x_offset, self.height-70, 60, 60)
color = self.colors['primary'] if i == self.project['current_sprite'] else self.colors['panel']
hover_color = self.lighten_color(color, 0.2)
current_color = hover_color if self.hover_sprite == i else color
pygame.draw.rect(self.screen, current_color, sprite_rect, border_radius=10)
pygame.draw.rect(self.screen, self.darken_color(current_color), sprite_rect, 2, border_radius=10)
# عرض المظهر الحالي للكائن
if sprite['costumes']:
costume = sprite['costumes'][sprite['current_costume']]
scaled_img = pygame.transform.scale(costume['image'], (40, 40))
self.screen.blit(scaled_img, (x_offset + 10, self.height-65))
x_offset += 70
# زر إضافة كائن جديد
add_rect = pygame.Rect(x_offset, self.height-65, 30, 30)
pygame.draw.rect(self.screen, self.colors['secondary'], add_rect, border_radius=15)
add_text = self.title_font.render("+", True, (255, 255, 255))
self.screen.blit(add_text, (x_offset + 10, self.height-60))
return add_rect
def draw_tutorial(self):
"""رسم فقاعة المساعدة التفاعلية"""
if self.show_tutorial:
help_rect = pygame.Rect(300, 100, 350, 180)
pygame.draw.rect(self.screen, (255, 255, 255), help_rect, border_radius=20)
pygame.draw.rect(self.screen, self.colors['primary'], help_rect, 2, border_radius=20)
# رأس المساعدة
pygame.draw.rect(self.screen, self.colors['primary'], (300, 100, 350, 40),
border_top_left_radius=20, border_top_right_radius=20)
title = self.title_font.render("كيف تبدأ؟", True, (255, 255, 255))
self.screen.blit(title, (320, 110))
# محتوى المساعدة
help_text = [
"1. اسحب الكتل من اللوحة اليسرى",
"2. أفلتها في مساحة العمل",
"3. صل الكتل مع بعضها",
"4. اضغط على تشغيل لتنفيذ البرنامج",
"5. استخدم تبويب الكائنات لإدارة الشخصيات"
]
for i, line in enumerate(help_text):
text = self.font.render(line, True, self.colors['text'])
self.screen.blit(text, (320, 150 + i*25))
# زر إغلاق
close_rect = pygame.Rect(620, 110, 20, 20)
pygame.draw.rect(self.screen, self.colors['danger'], close_rect, border_radius=10)
close_text = self.font.render("✕", True, (255, 255, 255))
self.screen.blit(close_text, (625, 110))
return close_rect
return None
def play_sound(self, name):
"""تشغيل صوت مع ضبط مستوى الصوت"""
if name in self.sounds and self.sounds[name]:
self.sounds[name].set_volume(self.project['volume'] / 100)
self.sounds[name].play()
def execute_scripts(self):
"""تنفيذ السكربتات مع دعم الأصوات"""
self.running = True
self.output = "جاري التنفيذ..."
self.play_sound('success')
sprite = self.project['sprites'][self.project['current_sprite']]
for script in self.project['scripts'][self.current_tab]:
if script['event']['type'] == 'on_start':
for block in script['blocks']:
try:
if block['type'] == 'move':
steps = int(block['inputs'][0].get('value', 10))
sprite['x'] += steps
self.output += f"\nتحرك {steps} خطوة"
elif block['type'] == 'play_sound':
sound_name = block['inputs'][0].get('value', 'نقر')
self.play_sound(sound_name)
self.output += f"\nتشغيل صوت: {sound_name}"
# يمكن إضافة المزيد من الأوامر هنا
except Exception as e:
self.output += f"\nخطأ: {str(e)}"
self.play_sound('error')
self.output += "\nتم التنفيذ بنجاح"
self.running = False
def run(self):
"""الحلقة الرئيسية للتطبيق"""
clock = pygame.time.Clock()
running = True
while running:
mouse_pos = pygame.mouse.get_pos()
self.hover_button = None
self.hover_tab = None
self.hover_sprite = None
# معالجة الأحداث
for event in pygame.event.get():
if event.type == QUIT:
running = False
elif event.type == MOUSEBUTTONDOWN:
# التحقق من النقر على الكتل
if 10 <= mouse_pos[0] <= 260 and 50 <= mouse_pos[1] <= self.height-110:
y_offset = 100
block_clicked = None
for category, blocks in self.blocks.items():
y_offset += 30
for block in blocks:
block_rect = pygame.Rect(20, y_offset, 220, 50)
if block_rect.collidepoint(mouse_pos):
block_clicked = block.copy()
self.drag_offset = (mouse_pos[0] - 20, mouse_pos[1] - y_offset)
self.play_sound('click')
break
y_offset += 60
if block_clicked: break
if block_clicked:
self.dragging = True
self.current_block = block_clicked
# التحقق من النقر على الأزرار الأخرى
elif self.hover_tab is not None:
self.current_tab = self.hover_tab
self.play_sound('click')
elif self.hover_sprite is not None:
self.project['current_sprite'] = self.hover_sprite
self.play_sound('connect')
elif self.hover_button == 'toolbar':
self.play_sound('click')
elif event.type == MOUSEBUTTONUP:
if self.dragging and self.current_block:
# إذا تم إسقاط الكتلة في مساحة العمل
if 270 <= mouse_pos[0] <= self.width-10 and 50 <= mouse_pos[1] <= self.height-70:
if self.current_block['type'].startswith('on_'):
self.project['scripts'][self.current_tab].append({
'event': self.current_block,
'blocks': []
})
else:
if self.project['scripts'][self.current_tab]:
self.project['scripts'][self.current_tab][-1]['blocks'].append(self.current_block)
else:
self.project['scripts'][self.current_tab].append({
'event': {'type': 'on_start', 'name': 'عند البدء', 'inputs': []},
'blocks': [self.current_block]
})
self.play_sound('connect')
self.dragging = False
self.current_block = None
elif event.type == MOUSEMOTION:
if self.dragging and self.current_block:
self.current_block['x'] = mouse_pos[0] - self.drag_offset[0]
self.current_block['y'] = mouse_pos[1] - self.drag_offset[1]
# الرسم
self.screen.fill(self.colors['background'])
self.draw_palette()
self.draw_workspace()
self.draw_tabs()
self.draw_toolbar()
self.draw_sprite_panel()
self.draw_output()
# تحديد العناصر التي يتم hover عليها
close_rect = self.draw_tutorial()
if close_rect and close_rect.collidepoint(mouse_pos):
if pygame.mouse.get_pressed()[0]:
self.show_tutorial = False
pygame.display.flip()
clock.tick(60)
pygame.quit()
if __name__ == "__main__":
app = ScratchLikeApp()
app.run()
الخميس، 3 أبريل 2025
import tkinter as tk
from tkinter import ttk, filedialog
from PIL import Image, ImageDraw, ImageTk
import os
class SimplePaintWithSave:
def __init__(self, root):
self.root = root
self.root.title("برنامج الرسم مع الحفظ")
# إعدادات الرسم
self.canvas_width = 800
self.canvas_height = 600
self.current_color = "black"
self.line_width = 3
# إنشاء عناصر الواجهة
self.create_widgets()
# متغيرات تتبع الرسم
self.last_x = None
self.last_y = None
self.drawing = False
# صورة الخلفية للتتبع
self.image = Image.new("RGB", (self.canvas_width, self.canvas_height), "white")
self.draw = ImageDraw.Draw(self.image)
def create_widgets(self):
# شريط الأدوات العلوي
toolbar = ttk.Frame(self.root)
toolbar.pack(fill=tk.X, padx=5, pady=5)
# أزرار الألوان
colors = ["black", "red", "green", "blue", "yellow", "purple"]
for color in colors:
btn = tk.Button(toolbar, bg=color, width=3,
command=lambda c=color: self.set_color(c))
btn.pack(side=tk.LEFT, padx=2)
# زر المسح
clear_btn = ttk.Button(toolbar, text="مسح الكل", command=self.clear_canvas)
clear_btn.pack(side=tk.LEFT, padx=5)
# زر الحفظ
save_btn = ttk.Button(toolbar, text="حفظ كصورة", command=self.save_image)
save_btn.pack(side=tk.RIGHT)
# لوحة الرسم
self.canvas = tk.Canvas(self.root, width=self.canvas_width,
height=self.canvas_height, bg="white")
self.canvas.pack(fill=tk.BOTH, expand=True)
# ربط أحداث الماوس
self.canvas.bind("", self.start_drawing)
self.canvas.bind("", self.draw)
self.canvas.bind("", self.stop_drawing)
def set_color(self, new_color):
self.current_color = new_color
def start_drawing(self, event):
self.drawing = True
self.last_x = event.x
self.last_y = event.y
def draw(self, event):
if self.drawing:
# الرسم على Canvas
self.canvas.create_line(
self.last_x, self.last_y, event.x, event.y,
width=self.line_width,
fill=self.current_color,
capstyle=tk.ROUND,
smooth=True
)
# الرسم على صورة PIL
self.draw.line(
[(self.last_x, self.last_y), (event.x, event.y)],
fill=self.current_color,
width=self.line_width
)
self.last_x = event.x
self.last_y = event.y
def stop_drawing(self, event):
self.drawing = False
def clear_canvas(self):
self.canvas.delete("all")
self.image = Image.new("RGB", (self.canvas_width, self.canvas_height), "white")
self.draw = ImageDraw.Draw(self.image)
def save_image(self):
try:
# اختيار مكان الحفظ
file_path = filedialog.asksaveasfilename(
defaultextension=".png",
filetypes=[("PNG Image", "*.png"), ("JPEG Image", "*.jpg"), ("All Files", "*.*")],
title="حفظ الصورة"
)
if file_path:
# حفظ الصورة بنفس نوع الملف المحدد
if file_path.lower().endswith('.jpg') or file_path.lower().endswith('.jpeg'):
self.image.save(file_path, "JPEG", quality=95)
else:
self.image.save(file_path, "PNG")
print(f"تم الحفظ بنجاح: {os.path.basename(file_path)}")
tk.messagebox.showinfo("تم الحفظ", f"تم حفظ الصورة في:\n{file_path}")
except Exception as e:
tk.messagebox.showerror("خطأ", f"حدث خطأ أثناء الحفظ:\n{str(e)}")
if __name__ == "__main__":
root = tk.Tk()
root.geometry("900x700")
root.minsize(400, 300)
# تحسين المظهر
style = ttk.Style()
style.configure("TButton", padding=5)
app = SimplePaintWithSave(root)
root.mainloop()
import tkinter as tk
from tkinter import ttk
class SimplePaint:
def __init__(self, root):
self.root = root
self.root.title("برنامج الرسم - Python 3.13.2")
# إعدادات أساسية
self.canvas_width = 800
self.canvas_height = 600
self.current_color = "black"
self.line_width = 3
# إنشاء عناصر الواجهة
self.create_widgets()
# متغيرات تتبع الرسم
self.last_x = None
self.last_y = None
def create_widgets(self):
# شريط الأدوات
toolbar = ttk.Frame(self.root)
toolbar.pack(fill=tk.X, padx=5, pady=5)
# أزرار الألوان
colors = ["black", "red", "green", "blue", "yellow", "purple"]
for color in colors:
btn = tk.Button(toolbar, bg=color, width=3,
command=lambda c=color: self.set_color(c))
btn.pack(side=tk.LEFT, padx=2)
# زر المسح
clear_btn = ttk.Button(toolbar, text="مسح الكل", command=self.clear_canvas)
clear_btn.pack(side=tk.RIGHT)
# لوحة الرسم
self.canvas = tk.Canvas(self.root, width=self.canvas_width,
height=self.canvas_height, bg="white")
self.canvas.pack(fill=tk.BOTH, expand=True)
# ربط أحداث الماوس
self.canvas.bind("", self.start_drawing)
self.canvas.bind("", self.draw)
self.canvas.bind("", self.stop_drawing)
def set_color(self, new_color):
self.current_color = new_color
def start_drawing(self, event):
self.last_x = event.x
self.last_y = event.y
def draw(self, event):
if self.last_x and self.last_y:
self.canvas.create_line(
self.last_x, self.last_y, event.x, event.y,
width=self.line_width,
fill=self.current_color,
capstyle=tk.ROUND,
smooth=True
)
self.last_x = event.x
self.last_y = event.y
def stop_drawing(self, event):
self.last_x = None
self.last_y = None
def clear_canvas(self):
self.canvas.delete("all")
if __name__ == "__main__":
# إعداد النافذة الرئيسية
root = tk.Tk()
# تحسينات للتشغيل على 3.13.2
root.tk.call('tk', 'scaling', 1.5) # تحسين الدقة للشاشات الحديثة
# ضبط حجم النافذة
root.geometry("900x700")
root.minsize(400, 300)
# تشغيل التطبيق
app = SimplePaint(root)
# التحقق من الإصدار
print(f"يعمل على Python {tk.TkVersion}")
root.mainloop()
الاشتراك في:
الرسائل (Atom)