EGYADMIN commited on
Commit
e05a890
·
verified ·
1 Parent(s): a81155a

Delete styling

Browse files
Files changed (4) hide show
  1. styling/charts.py +0 -282
  2. styling/enhanced_ui.py +0 -586
  3. styling/icons.py +0 -609
  4. styling/theme.py +0 -541
styling/charts.py DELETED
@@ -1,282 +0,0 @@
1
- """
2
- مولد الرسوم البيانية لنظام إدارة المناقصات
3
- """
4
-
5
- import os
6
- import numpy as np
7
- import matplotlib.pyplot as plt
8
- import matplotlib as mpl
9
- from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
10
- import tkinter as tk
11
- import customtkinter as ctk
12
-
13
- class ChartGenerator:
14
- """فئة مولد الرسوم البيانية"""
15
-
16
- def __init__(self, theme):
17
- """تهيئة مولد الرسوم البيانية"""
18
- self.theme = theme
19
-
20
- # تحديد مسار مجلد الرسوم البيانية
21
- self.charts_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "data", "charts")
22
-
23
- # إنشاء مجلد الرسوم البيانية إذا لم يكن موجودًا
24
- os.makedirs(self.charts_dir, exist_ok=True)
25
-
26
- # تهيئة نمط الرسوم البيانية
27
- self._setup_chart_style()
28
-
29
- def _setup_chart_style(self):
30
- """إعداد نمط الرسوم البيانية"""
31
- # تعيين نمط الرسوم البيانية
32
- plt.style.use('ggplot')
33
-
34
- # تعيين الخط
35
- plt.rcParams['font.family'] = 'sans-serif'
36
- plt.rcParams['font.sans-serif'] = ['Arial', 'DejaVu Sans', 'Liberation Sans', 'Bitstream Vera Sans', 'sans-serif']
37
-
38
- # تعيين حجم الخط
39
- plt.rcParams['font.size'] = 10
40
- plt.rcParams['axes.titlesize'] = 14
41
- plt.rcParams['axes.labelsize'] = 12
42
- plt.rcParams['xtick.labelsize'] = 10
43
- plt.rcParams['ytick.labelsize'] = 10
44
- plt.rcParams['legend.fontsize'] = 10
45
-
46
- # تعيين الألوان
47
- if self.theme.current_theme == "light":
48
- plt.rcParams['figure.facecolor'] = self.theme.LIGHT_CARD_BG_COLOR
49
- plt.rcParams['axes.facecolor'] = self.theme.LIGHT_BG_COLOR
50
- plt.rcParams['axes.edgecolor'] = self.theme.LIGHT_BORDER_COLOR
51
- plt.rcParams['axes.labelcolor'] = self.theme.LIGHT_FG_COLOR
52
- plt.rcParams['xtick.color'] = self.theme.LIGHT_FG_COLOR
53
- plt.rcParams['ytick.color'] = self.theme.LIGHT_FG_COLOR
54
- plt.rcParams['text.color'] = self.theme.LIGHT_FG_COLOR
55
- plt.rcParams['grid.color'] = self.theme.LIGHT_BORDER_COLOR
56
- else:
57
- plt.rcParams['figure.facecolor'] = self.theme.DARK_CARD_BG_COLOR
58
- plt.rcParams['axes.facecolor'] = self.theme.DARK_BG_COLOR
59
- plt.rcParams['axes.edgecolor'] = self.theme.DARK_BORDER_COLOR
60
- plt.rcParams['axes.labelcolor'] = self.theme.DARK_FG_COLOR
61
- plt.rcParams['xtick.color'] = self.theme.DARK_FG_COLOR
62
- plt.rcParams['ytick.color'] = self.theme.DARK_FG_COLOR
63
- plt.rcParams['text.color'] = self.theme.DARK_FG_COLOR
64
- plt.rcParams['grid.color'] = self.theme.DARK_BORDER_COLOR
65
-
66
- def create_bar_chart(self, data, title, xlabel, ylabel):
67
- """إنشاء رسم بياني شريطي"""
68
- # إنشاء الشكل والمحاور
69
- fig, ax = plt.subplots(figsize=(8, 5), dpi=100)
70
-
71
- # رسم الرسم البياني الشريطي
72
- bars = ax.bar(data['labels'], data['values'], color=self.theme.PRIMARY_COLOR[self.theme.current_theme])
73
-
74
- # إضافة القيم فوق الأشرطة
75
- for bar in bars:
76
- height = bar.get_height()
77
- ax.text(bar.get_x() + bar.get_width() / 2., height + 0.1 * max(data['values']),
78
- f'{height:,.0f}', ha='center', va='bottom')
79
-
80
- # تعيين العنوان والتسميات
81
- ax.set_title(title)
82
- ax.set_xlabel(xlabel)
83
- ax.set_ylabel(ylabel)
84
-
85
- # تعيين حدود المحور y
86
- ax.set_ylim(0, max(data['values']) * 1.2)
87
-
88
- # إضافة الشبكة
89
- ax.grid(True, linestyle='--', alpha=0.7)
90
-
91
- # تضييق الشكل
92
- fig.tight_layout()
93
-
94
- return fig
95
-
96
- def create_line_chart(self, data, title, xlabel, ylabel):
97
- """إنشاء رسم بياني خطي"""
98
- # إنشاء الشكل والمحاور
99
- fig, ax = plt.subplots(figsize=(8, 5), dpi=100)
100
-
101
- # رسم الرسم البياني الخطي
102
- line = ax.plot(data['labels'], data['values'], marker='o', linestyle='-', linewidth=2,
103
- color=self.theme.PRIMARY_COLOR[self.theme.current_theme],
104
- markersize=8, markerfacecolor=self.theme.SECONDARY_COLOR[self.theme.current_theme])
105
-
106
- # إضافة القيم فوق النقاط
107
- for i, value in enumerate(data['values']):
108
- ax.text(i, value + 0.05 * max(data['values']), f'{value:,.0f}', ha='center', va='bottom')
109
-
110
- # تعيين العنوان والتسميات
111
- ax.set_title(title)
112
- ax.set_xlabel(xlabel)
113
- ax.set_ylabel(ylabel)
114
-
115
- # تعيي�� حدود المحور y
116
- ax.set_ylim(0, max(data['values']) * 1.2)
117
-
118
- # إضافة الشبكة
119
- ax.grid(True, linestyle='--', alpha=0.7)
120
-
121
- # تضييق الشكل
122
- fig.tight_layout()
123
-
124
- return fig
125
-
126
- def create_pie_chart(self, data, title):
127
- """إنشاء رسم بياني دائري"""
128
- # إنشاء الشكل والمحاور
129
- fig, ax = plt.subplots(figsize=(8, 5), dpi=100)
130
-
131
- # تعيين الألوان
132
- colors = [
133
- self.theme.PRIMARY_COLOR[self.theme.current_theme],
134
- self.theme.SECONDARY_COLOR[self.theme.current_theme],
135
- self.theme.ACCENT_COLOR[self.theme.current_theme],
136
- self.theme.WARNING_COLOR[self.theme.current_theme],
137
- self.theme.SUCCESS_COLOR[self.theme.current_theme]
138
- ]
139
-
140
- # رسم الرسم البياني الدائري
141
- wedges, texts, autotexts = ax.pie(
142
- data['values'],
143
- labels=data['labels'],
144
- autopct='%1.1f%%',
145
- startangle=90,
146
- colors=colors,
147
- wedgeprops={'edgecolor': 'white', 'linewidth': 1},
148
- textprops={'color': self.theme.get_color('fg_color')}
149
- )
150
-
151
- # تعيين خصائص النص
152
- for autotext in autotexts:
153
- autotext.set_color('white')
154
- autotext.set_fontweight('bold')
155
-
156
- # تعيين العنوان
157
- ax.set_title(title)
158
-
159
- # جعل الرسم البياني دائريًا
160
- ax.axis('equal')
161
-
162
- # تضييق الشكل
163
- fig.tight_layout()
164
-
165
- return fig
166
-
167
- def create_stacked_bar_chart(self, data, title, xlabel, ylabel):
168
- """إنشاء رسم بياني شريطي متراكم"""
169
- # إنشاء الشكل والمحاور
170
- fig, ax = plt.subplots(figsize=(8, 5), dpi=100)
171
-
172
- # تعيين الألوان
173
- colors = [
174
- self.theme.PRIMARY_COLOR[self.theme.current_theme],
175
- self.theme.SECONDARY_COLOR[self.theme.current_theme],
176
- self.theme.ACCENT_COLOR[self.theme.current_theme],
177
- self.theme.WARNING_COLOR[self.theme.current_theme],
178
- self.theme.SUCCESS_COLOR[self.theme.current_theme]
179
- ]
180
-
181
- # رسم الرسم البياني الشريطي المتراكم
182
- bottom = np.zeros(len(data['labels']))
183
- for i, category in enumerate(data['categories']):
184
- values = data['values'][i]
185
- bars = ax.bar(data['labels'], values, bottom=bottom, label=category, color=colors[i % len(colors)])
186
- bottom += values
187
-
188
- # تعيين العنوان والتسميات
189
- ax.set_title(title)
190
- ax.set_xlabel(xlabel)
191
- ax.set_ylabel(ylabel)
192
-
193
- # إضافة وسيلة إيضاح
194
- ax.legend()
195
-
196
- # إضافة الشبكة
197
- ax.grid(True, linestyle='--', alpha=0.7)
198
-
199
- # تضييق الشكل
200
- fig.tight_layout()
201
-
202
- return fig
203
-
204
- def create_risk_matrix(self, data, title):
205
- """إنشاء مصفوفة المخاطر"""
206
- # إنشاء الشكل والمحاور
207
- fig, ax = plt.subplots(figsize=(8, 5), dpi=100)
208
-
209
- # تعيين الألوان
210
- colors = {
211
- 'منخفض': self.theme.SUCCESS_COLOR[self.theme.current_theme],
212
- 'متوسط': self.theme.WARNING_COLOR[self.theme.current_theme],
213
- 'عالي': self.theme.ERROR_COLOR[self.theme.current_theme]
214
- }
215
-
216
- # تعيين قيم المحاور
217
- probability_values = {'منخفض': 1, 'متوسط': 2, 'عالي': 3}
218
- impact_values = {'منخفض': 1, 'متوسط': 2, 'عالي': 3}
219
-
220
- # رسم المصفوفة
221
- for risk in data['risks']:
222
- prob = probability_values[risk['probability']]
223
- impact = impact_values[risk['impact']]
224
- color = colors[risk['probability']] if prob > impact else colors[risk['impact']]
225
- ax.scatter(impact, prob, color=color, s=100, alpha=0.7)
226
- ax.annotate(risk['name'], (impact, prob), xytext=(5, 5), textcoords='offset points')
227
-
228
- # تعيين حدود المحاور
229
- ax.set_xlim(0.5, 3.5)
230
- ax.set_ylim(0.5, 3.5)
231
-
232
- # تعيين تسميات المحاور
233
- ax.set_xticks([1, 2, 3])
234
- ax.set_xticklabels(['منخفض', 'متوسط', 'عالي'])
235
- ax.set_yticks([1, 2, 3])
236
- ax.set_yticklabels(['منخفض', 'متوسط', 'عالي'])
237
-
238
- # تعيين العنوان والتسميات
239
- ax.set_title(title)
240
- ax.set_xlabel('التأثير')
241
- ax.set_ylabel('الاحتمالية')
242
-
243
- # إضافة الشبكة
244
- ax.grid(True, linestyle='--', alpha=0.7)
245
-
246
- # إضافة مناطق المخاطر
247
- # منطقة المخاطر المنخفضة (أخضر)
248
- ax.add_patch(plt.Rectangle((0.5, 0.5), 1, 1, fill=True, color=self.theme.SUCCESS_COLOR[self.theme.current_theme], alpha=0.1))
249
- # منطقة المخاطر المتوسطة (أصفر)
250
- ax.add_patch(plt.Rectangle((1.5, 0.5), 1, 1, fill=True, color=self.theme.WARNING_COLOR[self.theme.current_theme], alpha=0.1))
251
- ax.add_patch(plt.Rectangle((0.5, 1.5), 1, 1, fill=True, color=self.theme.WARNING_COLOR[self.theme.current_theme], alpha=0.1))
252
- # منطقة المخاطر العالية (أحمر)
253
- ax.add_patch(plt.Rectangle((2.5, 0.5), 1, 3, fill=True, color=self.theme.ERROR_COLOR[self.theme.current_theme], alpha=0.1))
254
- ax.add_patch(plt.Rectangle((0.5, 2.5), 2, 1, fill=True, color=self.theme.ERROR_COLOR[self.theme.current_theme], alpha=0.1))
255
- ax.add_patch(plt.Rectangle((1.5, 1.5), 1, 1, fill=True, color=self.theme.ERROR_COLOR[self.theme.current_theme], alpha=0.1))
256
-
257
- # تضييق الشكل
258
- fig.tight_layout()
259
-
260
- return fig
261
-
262
- def embed_chart_in_frame(self, parent, fig):
263
- """تضمين الرسم البياني في إطار"""
264
- # إنشاء إطار للرسم البياني
265
- chart_frame = ctk.CTkFrame(parent, fg_color="transparent")
266
-
267
- # تضمين الرسم البياني في الإطار
268
- canvas = FigureCanvasTkAgg(fig, master=chart_frame)
269
- canvas.draw()
270
- canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
271
-
272
- return chart_frame
273
-
274
- def save_chart(self, fig, name):
275
- """حفظ الرسم البياني"""
276
- # تحديد مسار الملف
277
- file_path = os.path.join(self.charts_dir, f"{name}.png")
278
-
279
- # حفظ الرسم البياني
280
- fig.savefig(file_path, dpi=100, bbox_inches='tight')
281
-
282
- return file_path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
styling/enhanced_ui.py DELETED
@@ -1,586 +0,0 @@
1
- """
2
- محسن واجهة المستخدم - نظام تحليل المناقصات
3
- """
4
-
5
- import streamlit as st
6
- import pandas as pd
7
- import numpy as np
8
- import base64
9
- from pathlib import Path
10
- import os
11
-
12
- class UIEnhancer:
13
- """فئة لتحسين واجهة المستخدم وتوحيد التصميم عبر النظام"""
14
-
15
- # ألوان النظام
16
- COLORS = {
17
- 'primary': '#1E88E5', # أزرق
18
- 'secondary': '#5E35B1', # بنفسجي
19
- 'success': '#43A047', # أخضر
20
- 'warning': '#FB8C00', # برتقالي
21
- 'danger': '#E53935', # أحمر
22
- 'info': '#00ACC1', # سماوي
23
- 'light': '#F5F5F5', # رمادي فاتح
24
- 'dark': '#212121', # رمادي داكن
25
- 'accent': '#FF4081', # وردي
26
- 'background': '#FFFFFF', # أبيض
27
- 'text': '#212121', # أسود
28
- 'border': '#E0E0E0' # رمادي حدود
29
- }
30
-
31
- # أحجام الخطوط
32
- FONT_SIZES = {
33
- 'xs': '0.75rem',
34
- 'sm': '0.875rem',
35
- 'md': '1rem',
36
- 'lg': '1.125rem',
37
- 'xl': '1.25rem',
38
- '2xl': '1.5rem',
39
- '3xl': '1.875rem',
40
- '4xl': '2.25rem',
41
- '5xl': '3rem'
42
- }
43
-
44
- def __init__(self, page_title="نظام تحليل المناقصات", page_icon="📊"):
45
- """تهيئة محسن واجهة المستخدم"""
46
- self.page_title = page_title
47
- self.page_icon = page_icon
48
- self.theme_mode = "light" # الوضع الافتراضي هو الوضع الفاتح
49
-
50
- def apply_global_styles(self):
51
- """تطبيق التنسيقات العامة على الصفحة"""
52
- # تعريف CSS العام
53
- css = f"""
54
- @import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@300;400;500;700&display=swap');
55
-
56
- * {{
57
- font-family: 'Tajawal', sans-serif;
58
- direction: rtl;
59
- }}
60
-
61
- h1, h2, h3, h4, h5, h6 {{
62
- font-family: 'Tajawal', sans-serif;
63
- font-weight: 700;
64
- color: {self.COLORS['dark']};
65
- }}
66
-
67
- .module-title {{
68
- color: {self.COLORS['primary']};
69
- font-size: {self.FONT_SIZES['3xl']};
70
- margin-bottom: 1rem;
71
- border-bottom: 2px solid {self.COLORS['primary']};
72
- padding-bottom: 0.5rem;
73
- }}
74
-
75
- .stTabs [data-baseweb="tab-list"] {{
76
- gap: 2px;
77
- }}
78
-
79
- .stTabs [data-baseweb="tab"] {{
80
- height: 50px;
81
- white-space: pre-wrap;
82
- background-color: {self.COLORS['light']};
83
- border-radius: 4px 4px 0 0;
84
- gap: 1px;
85
- padding-top: 10px;
86
- padding-bottom: 10px;
87
- }}
88
-
89
- .stTabs [aria-selected="true"] {{
90
- background-color: {self.COLORS['primary']};
91
- color: white;
92
- }}
93
-
94
- div[data-testid="stSidebarNav"] li div a span {{
95
- direction: rtl;
96
- text-align: right;
97
- font-family: 'Tajawal', sans-serif;
98
- }}
99
-
100
- div[data-testid="stSidebarNav"] {{
101
- background-color: {self.COLORS['light']};
102
- }}
103
-
104
- div[data-testid="stSidebarNav"] li div {{
105
- margin-right: 0;
106
- margin-left: auto;
107
- }}
108
-
109
- div[data-testid="stSidebarNav"] li div a {{
110
- padding-right: 10px;
111
- padding-left: 0;
112
- }}
113
-
114
- div[data-testid="stSidebarNav"] li div a:hover {{
115
- background-color: {self.COLORS['primary'] + '20'};
116
- }}
117
-
118
- div[data-testid="stSidebarNav"] li div[aria-selected="true"] {{
119
- background-color: {self.COLORS['primary'] + '40'};
120
- }}
121
-
122
- div[data-testid="stSidebarNav"] li div[aria-selected="true"] a span {{
123
- color: {self.COLORS['primary']};
124
- font-weight: 500;
125
- }}
126
-
127
- .metric-card {{
128
- background-color: white;
129
- border-radius: 10px;
130
- padding: 20px;
131
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
132
- text-align: center;
133
- transition: transform 0.3s ease;
134
- }}
135
-
136
- .metric-card:hover {{
137
- transform: translateY(-5px);
138
- }}
139
-
140
- .metric-value {{
141
- font-size: 2.5rem;
142
- font-weight: 700;
143
- margin: 10px 0;
144
- }}
145
-
146
- .metric-label {{
147
- font-size: 1rem;
148
- color: #666;
149
- }}
150
-
151
- .metric-change {{
152
- font-size: 0.9rem;
153
- margin-top: 5px;
154
- }}
155
-
156
- .metric-change-positive {{
157
- color: {self.COLORS['success']};
158
- }}
159
-
160
- .metric-change-negative {{
161
- color: {self.COLORS['danger']};
162
- }}
163
-
164
- .custom-button {{
165
- background-color: {self.COLORS['primary']};
166
- color: white;
167
- border: none;
168
- border-radius: 5px;
169
- padding: 10px 20px;
170
- font-size: 1rem;
171
- cursor: pointer;
172
- transition: background-color 0.3s ease;
173
- }}
174
-
175
- .custom-button:hover {{
176
- background-color: {self.COLORS['secondary']};
177
- }}
178
-
179
- .custom-card {{
180
- background-color: white;
181
- border-radius: 10px;
182
- padding: 20px;
183
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
184
- margin-bottom: 20px;
185
- }}
186
-
187
- .header-container {{
188
- display: flex;
189
- justify-content: space-between;
190
- align-items: center;
191
- margin-bottom: 2rem;
192
- padding-bottom: 1rem;
193
- border-bottom: 1px solid {self.COLORS['border']};
194
- }}
195
-
196
- .header-title {{
197
- color: {self.COLORS['primary']};
198
- font-size: {self.FONT_SIZES['3xl']};
199
- margin: 0;
200
- }}
201
-
202
- .header-subtitle {{
203
- color: {self.COLORS['dark']};
204
- font-size: {self.FONT_SIZES['lg']};
205
- margin: 0;
206
- }}
207
-
208
- .header-actions {{
209
- display: flex;
210
- gap: 10px;
211
- }}
212
-
213
- /* تنسيق الجداول */
214
- div[data-testid="stTable"] table {{
215
- width: 100%;
216
- border-collapse: collapse;
217
- }}
218
-
219
- div[data-testid="stTable"] thead tr th {{
220
- background-color: {self.COLORS['primary']};
221
- color: white;
222
- text-align: right;
223
- padding: 12px;
224
- }}
225
-
226
- div[data-testid="stTable"] tbody tr:nth-child(even) {{
227
- background-color: {self.COLORS['light']};
228
- }}
229
-
230
- div[data-testid="stTable"] tbody tr:hover {{
231
- background-color: {self.COLORS['primary'] + '10'};
232
- }}
233
-
234
- div[data-testid="stTable"] tbody tr td {{
235
- padding: 10px;
236
- text-align: right;
237
- }}
238
-
239
- /* تنسيق النماذج */
240
- div[data-testid="stForm"] {{
241
- background-color: white;
242
- border-radius: 10px;
243
- padding: 20px;
244
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
245
- }}
246
-
247
- button[kind="primaryFormSubmit"] {{
248
- background-color: {self.COLORS['primary']};
249
- color: white;
250
- }}
251
-
252
- button[kind="secondaryFormSubmit"] {{
253
- background-color: {self.COLORS['light']};
254
- color: {self.COLORS['dark']};
255
- border: 1px solid {self.COLORS['border']};
256
- }}
257
-
258
- /* تنسيق الرسوم البيانية */
259
- div[data-testid="stVegaLiteChart"] {{
260
- background-color: white;
261
- border-radius: 10px;
262
- padding: 20px;
263
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
264
- }}
265
- """
266
-
267
- # تطبيق CSS
268
- st.markdown(f'<style>{css}</style>', unsafe_allow_html=True)
269
-
270
- def apply_theme_colors(self):
271
- """تطبيق ألوان السمة الحالية"""
272
- # تحديد ألوان السمة بناءً على الوضع
273
- if self.theme_mode == "dark":
274
- self.COLORS['background'] = '#121212'
275
- self.COLORS['text'] = '#FFFFFF'
276
- self.COLORS['border'] = '#333333'
277
- else:
278
- self.COLORS['background'] = '#FFFFFF'
279
- self.COLORS['text'] = '#212121'
280
- self.COLORS['border'] = '#E0E0E0'
281
-
282
- # تطبيق CSS للسمة
283
- theme_css = f"""
284
- body {{
285
- background-color: {self.COLORS['background']};
286
- color: {self.COLORS['text']};
287
- }}
288
- """
289
-
290
- st.markdown(f'<style>{theme_css}</style>', unsafe_allow_html=True)
291
-
292
- def toggle_theme(self):
293
- """تبديل وضع السمة بين الفاتح والداكن"""
294
- if self.theme_mode == "light":
295
- self.theme_mode = "dark"
296
- else:
297
- self.theme_mode = "light"
298
-
299
- self.apply_theme_colors()
300
-
301
- def create_sidebar(self, menu_items):
302
- """إنشاء الشريط الجانبي مع قائمة العناصر"""
303
- # إنشاء معرف فريد للزر بناءً على عنوان الصفحة
304
- button_key = f"toggle_theme_button_{self.page_title}"
305
-
306
- with st.sidebar:
307
- # إضافة الشعار
308
- st.markdown(
309
- f"""
310
- <div style="text-align: center; margin-bottom: 20px;">
311
- <h2 style="color: {self.COLORS['primary']};">{self.page_icon} {self.page_title}</h2>
312
- </div>
313
- """,
314
- unsafe_allow_html=True
315
- )
316
-
317
- # إضافة معلومات المستخدم
318
- st.markdown(
319
- f"""
320
- <div style="text-align: center; margin-bottom: 20px;">
321
- <div style="width: 60px; height: 60px; border-radius: 50%; background-color: {self.COLORS['primary']}; color: white; display: flex; align-items: center; justify-content: center; margin: 0 auto; font-size: 24px; font-weight: bold;">
322
- م
323
- </div>
324
- <p style="margin-top: 10px; font-weight: bold;">محمد أحمد</p>
325
- <p style="margin-top: -15px; font-size: 0.8rem; color: #666;">مدير المشاريع</p>
326
- </div>
327
- """,
328
- unsafe_allow_html=True
329
- )
330
-
331
- st.divider()
332
-
333
- # إنشاء القائمة
334
- selected = st.radio(
335
- "القائمة الرئيسية",
336
- [item["name"] for item in menu_items],
337
- format_func=lambda x: x,
338
- label_visibility="collapsed"
339
- )
340
-
341
- st.divider()
342
-
343
- # إضافة زر تبديل السمة مع معرف فريد
344
- if st.button("تبديل السمة 🌓", key=button_key):
345
- self.toggle_theme()
346
- st.experimental_rerun()
347
-
348
- # إضافة معلومات النظام
349
- st.markdown(
350
- """
351
- <div style="position: absolute; bottom: 20px; left: 20px; right: 20px; text-align: center;">
352
- <p style="font-size: 0.8rem; color: #666;">نظام تحليل المناقصات | الإصدار 2.0.0</p>
353
- <p style="font-size: 0.7rem; color: #888;">© 2025 جميع الحقوق محفوظة</p>
354
- </div>
355
- """,
356
- unsafe_allow_html=True
357
- )
358
-
359
- return selected
360
-
361
- def create_header(self, title, subtitle=None, show_actions=True):
362
- """إنشاء ترويسة الصفحة"""
363
- # إنشاء معرفات فريدة للأزرار
364
- add_button_key = f"add_button_{title}"
365
- update_button_key = f"update_button_{title}"
366
-
367
- col1, col2 = st.columns([3, 1])
368
-
369
- with col1:
370
- st.markdown(f'<h1 class="header-title">{title}</h1>', unsafe_allow_html=True)
371
- if subtitle:
372
- st.markdown(f'<p class="header-subtitle">{subtitle}</p>', unsafe_allow_html=True)
373
-
374
- if show_actions:
375
- with col2:
376
- col2_1, col2_2 = st.columns(2)
377
- with col2_1:
378
- st.button("إضافة جديد", key=add_button_key)
379
- with col2_2:
380
- st.button("تحديث", key=update_button_key)
381
-
382
- st.divider()
383
-
384
- def create_metric_card(self, label, value, change=None, color=None):
385
- """إنشاء بطاقة مقياس"""
386
- if color is None:
387
- color = self.COLORS['primary']
388
-
389
- change_html = ""
390
- if change is not None:
391
- if change.startswith("+"):
392
- change_class = "metric-change-positive"
393
- change_icon = "↑"
394
- elif change.startswith("-"):
395
- change_class = "metric-change-negative"
396
- change_icon = "↓"
397
- else:
398
- change_class = ""
399
- change_icon = ""
400
-
401
- change_html = f'<div class="metric-change {change_class}">{change_icon} {change}</div>'
402
-
403
- st.markdown(
404
- f"""
405
- <div class="metric-card" style="border-top: 4px solid {color};">
406
- <div class="metric-label">{label}</div>
407
- <div class="metric-value" style="color: {color};">{value}</div>
408
- {change_html}
409
- </div>
410
- """,
411
- unsafe_allow_html=True
412
- )
413
-
414
- def create_card(self, title, content, color=None):
415
- """إنشاء بطاقة عامة"""
416
- if color is None:
417
- color = self.COLORS['primary']
418
-
419
- st.markdown(
420
- f"""
421
- <div class="custom-card" style="border-top: 4px solid {color};">
422
- <h3 style="color: {color}; margin-top: 0;">{title}</h3>
423
- <div>{content}</div>
424
- </div>
425
- """,
426
- unsafe_allow_html=True
427
- )
428
-
429
- def create_button(self, label, color=None, icon=None, key=None):
430
- """إنشاء زر مخصص"""
431
- if color is None:
432
- color = self.COLORS['primary']
433
-
434
- # إنشاء معرف فريد للزر إذا لم يتم توفيره
435
- if key is None:
436
- key = f"button_{label}_{hash(label)}"
437
-
438
- icon_html = f"{icon} " if icon else ""
439
-
440
- return st.button(
441
- f"{icon_html}{label}",
442
- key=key
443
- )
444
-
445
- def create_tabs(self, tab_names):
446
- """إنشاء تبويبات"""
447
- return st.tabs(tab_names)
448
-
449
- def create_expander(self, title, expanded=False, key=None):
450
- """إنشاء عنصر قابل للتوسيع"""
451
- # إنشاء معرف فريد للعنصر إذا لم يتم توفيره
452
- if key is None:
453
- key = f"expander_{title}_{hash(title)}"
454
-
455
- return st.expander(title, expanded=expanded, key=key)
456
-
457
- def create_data_table(self, data, use_container_width=True, hide_index=True):
458
- """إنشاء جدول بيانات"""
459
- return st.dataframe(data, use_container_width=use_container_width, hide_index=hide_index)
460
-
461
- def create_chart(self, chart_type, data, **kwargs):
462
- """إنشاء رسم بياني"""
463
- if chart_type == "bar":
464
- return st.bar_chart(data, **kwargs)
465
- elif chart_type == "line":
466
- return st.line_chart(data, **kwargs)
467
- elif chart_type == "area":
468
- return st.area_chart(data, **kwargs)
469
- else:
470
- return st.bar_chart(data, **kwargs)
471
-
472
- def create_form(self, title, key=None):
473
- """إنشاء نموذج"""
474
- # إنشاء معرف فريد للنموذج إذا لم يتم توفيره
475
- if key is None:
476
- key = f"form_{title}_{hash(title)}"
477
-
478
- return st.form(key=key)
479
-
480
- def create_file_uploader(self, label, types=None, key=None):
481
- """إنشاء أداة رفع الملفات"""
482
- # إنشاء معرف فريد لأداة رفع الملفات إذا لم يتم توفيره
483
- if key is None:
484
- key = f"file_uploader_{label}_{hash(label)}"
485
-
486
- return st.file_uploader(label, type=types, key=key)
487
-
488
- def create_date_input(self, label, value=None, key=None):
489
- """إنشاء حقل إدخال تاريخ"""
490
- # إنشاء معرف فريد لحقل إدخال التاريخ إذا لم يتم توفيره
491
- if key is None:
492
- key = f"date_input_{label}_{hash(label)}"
493
-
494
- return st.date_input(label, value=value, key=key)
495
-
496
- def create_select_box(self, label, options, index=0, key=None):
497
- """إنشاء قائمة منسدلة"""
498
- # إنشاء معرف فريد للقائمة المنسدلة إذا لم يتم توفيره
499
- if key is None:
500
- key = f"select_box_{label}_{hash(label)}"
501
-
502
- return st.selectbox(label, options, index=index, key=key)
503
-
504
- def create_multi_select(self, label, options, default=None, key=None):
505
- """إنشاء قائمة اختيار متعدد"""
506
- # إنشاء معرف فريد لقائمة الاختيار المتعدد إذا لم يتم توفيره
507
- if key is None:
508
- key = f"multi_select_{label}_{hash(label)}"
509
-
510
- return st.multiselect(label, options, default=default, key=key)
511
-
512
- def create_slider(self, label, min_value, max_value, value=None, step=1, key=None):
513
- """إنشاء شريط تمرير"""
514
- # إنشاء معرف فريد لشريط التمرير إذا لم يتم توفيره
515
- if key is None:
516
- key = f"slider_{label}_{hash(label)}"
517
-
518
- return st.slider(label, min_value=min_value, max_value=max_value, value=value, step=step, key=key)
519
-
520
- def create_text_input(self, label, value="", key=None):
521
- """إنشاء حقل إدخال نصي"""
522
- # إنشاء معرف فريد لحقل الإدخال النصي إذا لم يتم توفيره
523
- if key is None:
524
- key = f"text_input_{label}_{hash(label)}"
525
-
526
- return st.text_input(label, value=value, key=key)
527
-
528
- def create_text_area(self, label, value="", height=None, key=None):
529
- """إنشاء منطقة نص"""
530
- # إنشاء معرف فريد لمنطقة النص إذا لم يتم توفيره
531
- if key is None:
532
- key = f"text_area_{label}_{hash(label)}"
533
-
534
- return st.text_area(label, value=value, height=height, key=key)
535
-
536
- def create_number_input(self, label, min_value=None, max_value=None, value=0, step=1, key=None):
537
- """إنشاء حقل إدخال رقمي"""
538
- # إنشاء معرف فريد لحقل الإدخال الرقمي إذا لم يتم توفيره
539
- if key is None:
540
- key = f"number_input_{label}_{hash(label)}"
541
-
542
- return st.number_input(label, min_value=min_value, max_value=max_value, value=value, step=step, key=key)
543
-
544
- def create_checkbox(self, label, value=False, key=None):
545
- """إنشاء خانة اختيار"""
546
- # إنشاء معرف فريد لخانة الاختيار إذا لم يتم توفيره
547
- if key is None:
548
- key = f"checkbox_{label}_{hash(label)}"
549
-
550
- return st.checkbox(label, value=value, key=key)
551
-
552
- def create_radio(self, label, options, index=0, key=None):
553
- """إنشاء أزرار راديو"""
554
- # إنشاء معرف فريد لأزرار الراديو إذا لم يتم توفيره
555
- if key is None:
556
- key = f"radio_{label}_{hash(label)}"
557
-
558
- return st.radio(label, options, index=index, key=key)
559
-
560
- def create_progress_bar(self, value, key=None):
561
- """إنشاء شريط تقدم"""
562
- # إنشاء معرف فريد لشريط التقدم إذا لم يتم توفيره
563
- if key is None:
564
- key = f"progress_bar_{value}_{hash(str(value))}"
565
-
566
- return st.progress(value, key=key)
567
-
568
- def create_spinner(self, text="جاري التحميل..."):
569
- """إنشاء مؤشر تحميل"""
570
- return st.spinner(text)
571
-
572
- def create_success_message(self, message):
573
- """إنشاء رسالة نجاح"""
574
- return st.success(message)
575
-
576
- def create_error_message(self, message):
577
- """إنشاء رسالة خطأ"""
578
- return st.error(message)
579
-
580
- def create_warning_message(self, message):
581
- """إنشاء رسالة تحذير"""
582
- return st.warning(message)
583
-
584
- def create_info_message(self, message):
585
- """إنشاء رسالة معلومات"""
586
- return st.info(message)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
styling/icons.py DELETED
@@ -1,609 +0,0 @@
1
- """
2
- مولد الأيقونات لنظام إدارة المناقصات
3
- """
4
-
5
- import os
6
- import math
7
- from PIL import Image, ImageDraw, ImageFont
8
-
9
- class IconGenerator:
10
- """فئة مولد الأيقونات"""
11
-
12
- def __init__(self):
13
- """تهيئة مولد الأيقونات"""
14
- # تحديد مسار مجلد الأيقونات
15
- self.icons_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "assets", "icons")
16
-
17
- # إنشاء مجلد الأيقونات إذا لم يكن موجودًا
18
- os.makedirs(self.icons_dir, exist_ok=True)
19
-
20
- # تحديد حجم الأيقونة الافتراضي
21
- self.icon_size = (64, 64)
22
-
23
- # تحديد الألوان الافتراضية
24
- self.colors = {
25
- "primary": "#2980B9",
26
- "secondary": "#1ABC9C",
27
- "accent": "#9B59B6",
28
- "warning": "#F39C12",
29
- "error": "#E74C3C",
30
- "success": "#2ECC71",
31
- "white": "#FFFFFF",
32
- "black": "#333333",
33
- "gray": "#95A5A6"
34
- }
35
-
36
- def generate_icon(self, name, color=None, background_color=None, size=None):
37
- """توليد أيقونة"""
38
- # تحديد الألوان
39
- if color is None:
40
- color = self.colors["primary"]
41
-
42
- if background_color is None:
43
- background_color = self.colors["white"]
44
-
45
- # تحديد الحجم
46
- if size is None:
47
- size = self.icon_size
48
-
49
- # إنشاء صورة جديدة
50
- icon = Image.new("RGBA", size, background_color)
51
- draw = ImageDraw.Draw(icon)
52
-
53
- # رسم الأيقونة بناءً على الاسم
54
- if name == "dashboard":
55
- self._draw_dashboard_icon(draw, size, color)
56
- elif name == "projects":
57
- self._draw_projects_icon(draw, size, color)
58
- elif name == "documents":
59
- self._draw_documents_icon(draw, size, color)
60
- elif name == "pricing":
61
- self._draw_pricing_icon(draw, size, color)
62
- elif name == "resources":
63
- self._draw_resources_icon(draw, size, color)
64
- elif name == "risk":
65
- self._draw_risk_icon(draw, size, color)
66
- elif name == "reports":
67
- self._draw_reports_icon(draw, size, color)
68
- elif name == "ai":
69
- self._draw_ai_icon(draw, size, color)
70
- elif name == "settings":
71
- self._draw_settings_icon(draw, size, color)
72
- elif name == "logout":
73
- self._draw_logout_icon(draw, size, color)
74
- elif name == "search":
75
- self._draw_search_icon(draw, size, color)
76
- elif name == "add":
77
- self._draw_add_icon(draw, size, color)
78
- elif name == "upload":
79
- self._draw_upload_icon(draw, size, color)
80
- elif name == "import":
81
- self._draw_import_icon(draw, size, color)
82
- elif name == "export":
83
- self._draw_export_icon(draw, size, color)
84
- elif name == "save":
85
- self._draw_save_icon(draw, size, color)
86
- else:
87
- # أيقونة افتراضية
88
- self._draw_default_icon(draw, size, color)
89
-
90
- # حفظ الأيقونة
91
- icon_path = os.path.join(self.icons_dir, f"{name}.png")
92
- icon.save(icon_path)
93
-
94
- return icon_path
95
-
96
- def _draw_dashboard_icon(self, draw, size, color):
97
- """رسم أيقونة لوحة التحكم"""
98
- width, height = size
99
- padding = width // 8
100
-
101
- # رسم المربعات الأربعة
102
- box_size = (width - 3 * padding) // 2
103
-
104
- # المربع العلوي الأيسر
105
- draw.rectangle(
106
- [(padding, padding), (padding + box_size, padding + box_size)],
107
- fill=color
108
- )
109
-
110
- # المربع العلوي الأيمن
111
- draw.rectangle(
112
- [(2 * padding + box_size, padding), (2 * padding + 2 * box_size, padding + box_size)],
113
- fill=color
114
- )
115
-
116
- # المربع السفلي الأيسر
117
- draw.rectangle(
118
- [(padding, 2 * padding + box_size), (padding + box_size, 2 * padding + 2 * box_size)],
119
- fill=color
120
- )
121
-
122
- # المربع السفلي الأيمن
123
- draw.rectangle(
124
- [(2 * padding + box_size, 2 * padding + box_size), (2 * padding + 2 * box_size, 2 * padding + 2 * box_size)],
125
- fill=color
126
- )
127
-
128
- def _draw_projects_icon(self, draw, size, color):
129
- """رسم أيقونة المشاريع"""
130
- width, height = size
131
- padding = width // 8
132
-
133
- # رسم مجلد
134
- folder_points = [
135
- (padding, height // 3),
136
- (width // 3, height // 3),
137
- (width // 2, padding),
138
- (width - padding, padding),
139
- (width - padding, height - padding),
140
- (padding, height - padding)
141
- ]
142
- draw.polygon(folder_points, fill=color)
143
-
144
- def _draw_documents_icon(self, draw, size, color):
145
- """رسم أيقونة المستندات"""
146
- width, height = size
147
- padding = width // 8
148
-
149
- # رسم ورقة
150
- draw.rectangle(
151
- [(padding, padding), (width - padding, height - padding)],
152
- fill=color
153
- )
154
-
155
- # رسم خطوط النص
156
- line_padding = height // 8
157
- line_height = height // 20
158
- for i in range(4):
159
- y = padding + line_padding + i * (line_height + line_padding)
160
- draw.rectangle(
161
- [(padding * 2, y), (width - padding * 2, y + line_height)],
162
- fill=self.colors["white"]
163
- )
164
-
165
- def _draw_pricing_icon(self, draw, size, color):
166
- """رسم أيقونة التسعير"""
167
- width, height = size
168
- padding = width // 8
169
-
170
- # رسم علامة الدولار
171
- center_x = width // 2
172
- center_y = height // 2
173
- radius = min(width, height) // 3
174
-
175
- # رسم دائرة
176
- draw.ellipse(
177
- [(center_x - radius, center_y - radius), (center_x + radius, center_y + radius)],
178
- fill=color
179
- )
180
-
181
- # رسم علامة الدولار
182
- line_width = radius // 4
183
- draw.rectangle(
184
- [(center_x - line_width // 2, center_y - radius * 2 // 3), (center_x + line_width // 2, center_y + radius * 2 // 3)],
185
- fill=self.colors["white"]
186
- )
187
- draw.rectangle(
188
- [(center_x - radius * 2 // 3, center_y - line_width // 2), (center_x + radius * 2 // 3, center_y + line_width // 2)],
189
- fill=self.colors["white"]
190
- )
191
-
192
- def _draw_resources_icon(self, draw, size, color):
193
- """رسم أيقونة الموارد"""
194
- width, height = size
195
- padding = width // 8
196
-
197
- # رسم ثلاثة أشخاص
198
- center_x = width // 2
199
- center_y = height // 2
200
- radius = min(width, height) // 10
201
-
202
- # الشخص الأول (في الوسط)
203
- head_center_y = center_y - radius * 2
204
- draw.ellipse(
205
- [(center_x - radius, head_center_y - radius), (center_x + radius, head_center_y + radius)],
206
- fill=color
207
- )
208
- draw.polygon(
209
- [
210
- (center_x, head_center_y + radius),
211
- (center_x - radius * 2, center_y + radius * 3),
212
- (center_x + radius * 2, center_y + radius * 3)
213
- ],
214
- fill=color
215
- )
216
-
217
- # الشخص الثاني (على اليسار)
218
- left_center_x = center_x - radius * 4
219
- head_center_y = center_y - radius * 2
220
- draw.ellipse(
221
- [(left_center_x - radius, head_center_y - radius), (left_center_x + radius, head_center_y + radius)],
222
- fill=color
223
- )
224
- draw.polygon(
225
- [
226
- (left_center_x, head_center_y + radius),
227
- (left_center_x - radius * 2, center_y + radius * 3),
228
- (left_center_x + radius * 2, center_y + radius * 3)
229
- ],
230
- fill=color
231
- )
232
-
233
- # الشخص الثالث (على اليمين)
234
- right_center_x = center_x + radius * 4
235
- head_center_y = center_y - radius * 2
236
- draw.ellipse(
237
- [(right_center_x - radius, head_center_y - radius), (right_center_x + radius, head_center_y + radius)],
238
- fill=color
239
- )
240
- draw.polygon(
241
- [
242
- (right_center_x, head_center_y + radius),
243
- (right_center_x - radius * 2, center_y + radius * 3),
244
- (right_center_x + radius * 2, center_y + radius * 3)
245
- ],
246
- fill=color
247
- )
248
-
249
- def _draw_risk_icon(self, draw, size, color):
250
- """رسم أيقونة المخاطر"""
251
- width, height = size
252
- padding = width // 8
253
-
254
- # رسم علامة تحذير (مثلث)
255
- draw.polygon(
256
- [
257
- (width // 2, padding),
258
- (padding, height - padding),
259
- (width - padding, height - padding)
260
- ],
261
- fill=color
262
- )
263
-
264
- # رسم علامة التعجب
265
- exclamation_width = width // 10
266
- exclamation_height = height // 3
267
- center_x = width // 2
268
- center_y = height // 2
269
-
270
- # الجزء العلوي من علامة التعجب
271
- draw.rectangle(
272
- [
273
- (center_x - exclamation_width // 2, center_y - exclamation_height),
274
- (center_x + exclamation_width // 2, center_y)
275
- ],
276
- fill=self.colors["white"]
277
- )
278
-
279
- # النقطة السفلية من علامة التعجب
280
- dot_radius = exclamation_width
281
- draw.ellipse(
282
- [
283
- (center_x - dot_radius // 2, center_y + exclamation_height // 4),
284
- (center_x + dot_radius // 2, center_y + exclamation_height // 4 + dot_radius)
285
- ],
286
- fill=self.colors["white"]
287
- )
288
-
289
- def _draw_reports_icon(self, draw, size, color):
290
- """رسم أيقونة التقارير"""
291
- width, height = size
292
- padding = width // 8
293
-
294
- # رسم ورقة
295
- draw.rectangle(
296
- [(padding, padding), (width - padding, height - padding)],
297
- fill=color
298
- )
299
-
300
- # رسم رسم بياني
301
- chart_padding = width // 6
302
- chart_width = width - 2 * chart_padding
303
- chart_height = height // 2
304
- chart_bottom = height - chart_padding
305
-
306
- # رسم الأعمدة
307
- bar_width = chart_width // 5
308
- bar_spacing = bar_width // 2
309
-
310
- for i in range(4):
311
- bar_height = (i + 1) * chart_height // 4
312
- bar_x = chart_padding + i * (bar_width + bar_spacing)
313
- bar_y = chart_bottom - bar_height
314
-
315
- draw.rectangle(
316
- [(bar_x, bar_y), (bar_x + bar_width, chart_bottom)],
317
- fill=self.colors["white"]
318
- )
319
-
320
- def _draw_ai_icon(self, draw, size, color):
321
- """رسم أيقونة الذكاء الاصطناعي"""
322
- width, height = size
323
- padding = width // 8
324
-
325
- # رسم دماغ (مجرد تمثيل مبسط)
326
- center_x = width // 2
327
- center_y = height // 2
328
- brain_width = width - 2 * padding
329
- brain_height = height - 2 * padding
330
-
331
- # رسم الجزء الخارجي من الدماغ
332
- draw.ellipse(
333
- [(center_x - brain_width // 2, center_y - brain_height // 2), (center_x + brain_width // 2, center_y + brain_height // 2)],
334
- fill=color
335
- )
336
-
337
- # رسم خطوط الدماغ
338
- line_width = brain_width // 10
339
- line_spacing = brain_width // 8
340
-
341
- for i in range(-2, 3):
342
- y = center_y + i * line_spacing
343
- draw.line(
344
- [(center_x - brain_width // 3, y), (center_x + brain_width // 3, y)],
345
- fill=self.colors["white"],
346
- width=line_width
347
- )
348
-
349
- def _draw_settings_icon(self, draw, size, color):
350
- """رسم أيقونة الإعدادات"""
351
- width, height = size
352
- padding = width // 8
353
-
354
- # رسم ترس
355
- center_x = width // 2
356
- center_y = height // 2
357
- outer_radius = min(width, height) // 2 - padding
358
- inner_radius = outer_radius * 2 // 3
359
-
360
- # رسم الدائرة الداخلية
361
- draw.ellipse(
362
- [(center_x - inner_radius, center_y - inner_radius), (center_x + inner_radius, center_y + inner_radius)],
363
- fill=color
364
- )
365
-
366
- # رسم الأسنان
367
- num_teeth = 8
368
- tooth_width = outer_radius - inner_radius
369
-
370
- for i in range(num_teeth):
371
- angle = 2 * math.pi * i / num_teeth
372
- tooth_center_x = center_x + (inner_radius + tooth_width // 2) * math.cos(angle)
373
- tooth_center_y = center_y + (inner_radius + tooth_width // 2) * math.sin(angle)
374
-
375
- draw.ellipse(
376
- [
377
- (tooth_center_x - tooth_width // 2, tooth_center_y - tooth_width // 2),
378
- (tooth_center_x + tooth_width // 2, tooth_center_y + tooth_width // 2)
379
- ],
380
- fill=color
381
- )
382
-
383
- def _draw_logout_icon(self, draw, size, color):
384
- """رسم أيقونة تسجيل الخروج"""
385
- width, height = size
386
- padding = width // 8
387
-
388
- # رسم سهم الخروج
389
- arrow_width = width - 2 * padding
390
- arrow_height = height - 2 * padding
391
-
392
- # رسم المستطيل الرئيسي
393
- draw.rectangle(
394
- [(padding, padding), (width // 2, height - padding)],
395
- fill=color
396
- )
397
-
398
- # رسم السهم
399
- arrow_points = [
400
- (width // 2, height // 3),
401
- (width - padding, height // 2),
402
- (width // 2, height * 2 // 3),
403
- (width // 2, height // 2 + height // 8),
404
- (width // 2 + width // 4, height // 2 + height // 8),
405
- (width // 2 + width // 4, height // 2 - height // 8),
406
- (width // 2, height // 2 - height // 8)
407
- ]
408
- draw.polygon(arrow_points, fill=color)
409
-
410
- def _draw_search_icon(self, draw, size, color):
411
- """رسم أيقونة البحث"""
412
- width, height = size
413
- padding = width // 8
414
-
415
- # رسم دائرة البحث
416
- center_x = width // 2 - padding
417
- center_y = height // 2 - padding
418
- radius = min(width, height) // 3
419
-
420
- draw.ellipse(
421
- [(center_x - radius, center_y - radius), (center_x + radius, center_y + radius)],
422
- outline=color,
423
- width=radius // 3
424
- )
425
-
426
- # رسم مقبض البحث
427
- handle_width = radius // 3
428
- handle_length = radius
429
- handle_angle = math.pi / 4 # 45 درجة
430
-
431
- handle_start_x = center_x + radius * math.cos(handle_angle)
432
- handle_start_y = center_y + radius * math.sin(handle_angle)
433
- handle_end_x = handle_start_x + handle_length * math.cos(handle_angle)
434
- handle_end_y = handle_start_y + handle_length * math.sin(handle_angle)
435
-
436
- draw.line(
437
- [(handle_start_x, handle_start_y), (handle_end_x, handle_end_y)],
438
- fill=color,
439
- width=handle_width
440
- )
441
-
442
- def _draw_add_icon(self, draw, size, color):
443
- """رسم أيقونة الإضافة"""
444
- width, height = size
445
- padding = width // 8
446
-
447
- # رسم علامة الزائد
448
- center_x = width // 2
449
- center_y = height // 2
450
- line_length = min(width, height) - 2 * padding
451
- line_width = line_length // 5
452
-
453
- # الخط الأفقي
454
- draw.rectangle(
455
- [
456
- (center_x - line_length // 2, center_y - line_width // 2),
457
- (center_x + line_length // 2, center_y + line_width // 2)
458
- ],
459
- fill=color
460
- )
461
-
462
- # الخط الرأسي
463
- draw.rectangle(
464
- [
465
- (center_x - line_width // 2, center_y - line_length // 2),
466
- (center_x + line_width // 2, center_y + line_length // 2)
467
- ],
468
- fill=color
469
- )
470
-
471
- def _draw_upload_icon(self, draw, size, color):
472
- """رسم أيقونة التحميل"""
473
- width, height = size
474
- padding = width // 8
475
-
476
- # رسم سهم لأعلى
477
- center_x = width // 2
478
- arrow_width = width // 3
479
- arrow_height = height // 2
480
-
481
- # رسم السهم
482
- arrow_points = [
483
- (center_x, padding),
484
- (center_x + arrow_width, padding + arrow_height),
485
- (center_x + arrow_width // 2, padding + arrow_height),
486
- (center_x + arrow_width // 2, height - padding),
487
- (center_x - arrow_width // 2, height - padding),
488
- (center_x - arrow_width // 2, padding + arrow_height),
489
- (center_x - arrow_width, padding + arrow_height)
490
- ]
491
- draw.polygon(arrow_points, fill=color)
492
-
493
- def _draw_import_icon(self, draw, size, color):
494
- """رسم أيقونة الاستيراد"""
495
- width, height = size
496
- padding = width // 8
497
-
498
- # رسم سهم للداخل
499
- center_y = height // 2
500
- arrow_width = width // 2
501
- arrow_height = height // 3
502
-
503
- # رسم المستطيل
504
- draw.rectangle(
505
- [(width - padding - arrow_width // 2, padding), (width - padding, height - padding)],
506
- fill=color
507
- )
508
-
509
- # رسم السهم
510
- arrow_points = [
511
- (padding, center_y),
512
- (padding + arrow_width, center_y - arrow_height // 2),
513
- (padding + arrow_width, center_y - arrow_height // 4),
514
- (width - padding - arrow_width // 2, center_y - arrow_height // 4),
515
- (width - padding - arrow_width // 2, center_y + arrow_height // 4),
516
- (padding + arrow_width, center_y + arrow_height // 4),
517
- (padding + arrow_width, center_y + arrow_height // 2)
518
- ]
519
- draw.polygon(arrow_points, fill=color)
520
-
521
- def _draw_export_icon(self, draw, size, color):
522
- """رسم أيقونة التصدير"""
523
- width, height = size
524
- padding = width // 8
525
-
526
- # رسم سهم للخارج
527
- center_y = height // 2
528
- arrow_width = width // 2
529
- arrow_height = height // 3
530
-
531
- # رسم المستطيل
532
- draw.rectangle(
533
- [(padding, padding), (padding + arrow_width // 2, height - padding)],
534
- fill=color
535
- )
536
-
537
- # رسم السهم
538
- arrow_points = [
539
- (width - padding, center_y),
540
- (width - padding - arrow_width, center_y - arrow_height // 2),
541
- (width - padding - arrow_width, center_y - arrow_height // 4),
542
- (padding + arrow_width // 2, center_y - arrow_height // 4),
543
- (padding + arrow_width // 2, center_y + arrow_height // 4),
544
- (width - padding - arrow_width, center_y + arrow_height // 4),
545
- (width - padding - arrow_width, center_y + arrow_height // 2)
546
- ]
547
- draw.polygon(arrow_points, fill=color)
548
-
549
- def _draw_save_icon(self, draw, size, color):
550
- """رسم أيقونة الحفظ"""
551
- width, height = size
552
- padding = width // 8
553
-
554
- # رسم أيقونة القرص
555
- draw.rectangle(
556
- [(padding, padding), (width - padding, height - padding)],
557
- fill=color
558
- )
559
-
560
- # رسم الشريط العلوي
561
- draw.rectangle(
562
- [(padding * 2, padding * 2), (width - padding * 2, padding * 4)],
563
- fill=self.colors["white"]
564
- )
565
-
566
- # رسم المستطيل الداخلي
567
- draw.rectangle(
568
- [(width // 3, height // 2), (width * 2 // 3, height - padding * 2)],
569
- fill=self.colors["white"]
570
- )
571
-
572
- def _draw_default_icon(self, draw, size, color):
573
- """رسم أيقونة افتراضية"""
574
- width, height = size
575
- padding = width // 8
576
-
577
- # رسم دائرة
578
- center_x = width // 2
579
- center_y = height // 2
580
- radius = min(width, height) // 2 - padding
581
-
582
- draw.ellipse(
583
- [(center_x - radius, center_y - radius), (center_x + radius, center_y + radius)],
584
- fill=color
585
- )
586
-
587
- def generate_default_icons(self):
588
- """توليد الأيقونات الافتراضية"""
589
- icons = [
590
- "dashboard",
591
- "projects",
592
- "documents",
593
- "pricing",
594
- "resources",
595
- "risk",
596
- "reports",
597
- "ai",
598
- "settings",
599
- "logout",
600
- "search",
601
- "add",
602
- "upload",
603
- "import",
604
- "export",
605
- "save"
606
- ]
607
-
608
- for icon in icons:
609
- self.generate_icon(icon)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
styling/theme.py DELETED
@@ -1,541 +0,0 @@
1
- """
2
- ملف النمط لنظام إدارة المناقصات
3
- """
4
-
5
- import os
6
- import tkinter as tk
7
- import customtkinter as ctk
8
- from PIL import Image, ImageDraw
9
- import matplotlib.pyplot as plt
10
- from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
11
-
12
- class AppTheme:
13
- """فئة نمط التطبيق"""
14
-
15
- # ألوان النمط الفاتح
16
- LIGHT_BG_COLOR = "#F5F5F5"
17
- LIGHT_FG_COLOR = "#333333"
18
- LIGHT_CARD_BG_COLOR = "#FFFFFF"
19
- LIGHT_SIDEBAR_BG_COLOR = "#2C3E50"
20
- LIGHT_SIDEBAR_FG_COLOR = "#FFFFFF"
21
- LIGHT_SIDEBAR_HOVER_COLOR = "#34495E"
22
- LIGHT_SIDEBAR_ACTIVE_COLOR = "#1ABC9C"
23
- LIGHT_BUTTON_BG_COLOR = "#2980B9"
24
- LIGHT_BUTTON_HOVER_COLOR = "#3498DB"
25
- LIGHT_BUTTON_ACTIVE_COLOR = "#1F618D"
26
- LIGHT_INPUT_BG_COLOR = "#FFFFFF"
27
- LIGHT_INPUT_FG_COLOR = "#333333"
28
- LIGHT_BORDER_COLOR = "#E0E0E0"
29
-
30
- # ألوان النمط الداكن
31
- DARK_BG_COLOR = "#121212"
32
- DARK_FG_COLOR = "#E0E0E0"
33
- DARK_CARD_BG_COLOR = "#1E1E1E"
34
- DARK_SIDEBAR_BG_COLOR = "#1A1A2E"
35
- DARK_SIDEBAR_FG_COLOR = "#E0E0E0"
36
- DARK_SIDEBAR_HOVER_COLOR = "#16213E"
37
- DARK_SIDEBAR_ACTIVE_COLOR = "#0F3460"
38
- DARK_BUTTON_BG_COLOR = "#0F3460"
39
- DARK_BUTTON_HOVER_COLOR = "#16213E"
40
- DARK_BUTTON_ACTIVE_COLOR = "#1A1A2E"
41
- DARK_INPUT_BG_COLOR = "#2C2C2C"
42
- DARK_INPUT_FG_COLOR = "#E0E0E0"
43
- DARK_BORDER_COLOR = "#333333"
44
-
45
- # ألوان الأساسية
46
- PRIMARY_COLOR = {
47
- "light": "#2980B9",
48
- "dark": "#0F3460"
49
- }
50
-
51
- SECONDARY_COLOR = {
52
- "light": "#1ABC9C",
53
- "dark": "#16213E"
54
- }
55
-
56
- ACCENT_COLOR = {
57
- "light": "#9B59B6",
58
- "dark": "#533483"
59
- }
60
-
61
- WARNING_COLOR = {
62
- "light": "#F39C12",
63
- "dark": "#E58E26"
64
- }
65
-
66
- ERROR_COLOR = {
67
- "light": "#E74C3C",
68
- "dark": "#C0392B"
69
- }
70
-
71
- SUCCESS_COLOR = {
72
- "light": "#2ECC71",
73
- "dark": "#27AE60"
74
- }
75
-
76
- def __init__(self, config):
77
- """تهيئة النمط"""
78
- self.config = config
79
- self.current_theme = self.config.get_theme()
80
- self.font_family = self.config.get_font()
81
- self.font_size = self.config.get_font_size()
82
-
83
- # تهيئة النمط
84
- self._setup_theme()
85
-
86
- def _setup_theme(self):
87
- """إعداد النمط"""
88
- # تعيين نمط customtkinter
89
- ctk.set_appearance_mode(self.current_theme)
90
- ctk.set_default_color_theme("blue")
91
-
92
- # تهيئة الخطوط
93
- self.fonts = {
94
- "title": (self.font_family, self.font_size + 8, "bold"),
95
- "subtitle": (self.font_family, self.font_size + 4, "bold"),
96
- "heading": (self.font_family, self.font_size + 2, "bold"),
97
- "body": (self.font_family, self.font_size, "normal"),
98
- "small": (self.font_family, self.font_size - 2, "normal")
99
- }
100
-
101
- def apply_theme_to_app(self, app):
102
- """تطبيق النمط على التطبيق"""
103
- app.configure(fg_color=self.get_color("bg_color"))
104
-
105
- def get_color(self, color_name):
106
- """الحصول على لون معين"""
107
- if self.current_theme == "light":
108
- colors = {
109
- "bg_color": self.LIGHT_BG_COLOR,
110
- "fg_color": self.LIGHT_FG_COLOR,
111
- "card_bg_color": self.LIGHT_CARD_BG_COLOR,
112
- "sidebar_bg_color": self.LIGHT_SIDEBAR_BG_COLOR,
113
- "sidebar_fg_color": self.LIGHT_SIDEBAR_FG_COLOR,
114
- "sidebar_hover_color": self.LIGHT_SIDEBAR_HOVER_COLOR,
115
- "sidebar_active_color": self.LIGHT_SIDEBAR_ACTIVE_COLOR,
116
- "button_bg_color": self.LIGHT_BUTTON_BG_COLOR,
117
- "button_hover_color": self.LIGHT_BUTTON_HOVER_COLOR,
118
- "button_active_color": self.LIGHT_BUTTON_ACTIVE_COLOR,
119
- "input_bg_color": self.LIGHT_INPUT_BG_COLOR,
120
- "input_fg_color": self.LIGHT_INPUT_FG_COLOR,
121
- "border_color": self.LIGHT_BORDER_COLOR,
122
- "primary_color": self.PRIMARY_COLOR["light"],
123
- "secondary_color": self.SECONDARY_COLOR["light"],
124
- "accent_color": self.ACCENT_COLOR["light"],
125
- "warning_color": self.WARNING_COLOR["light"],
126
- "error_color": self.ERROR_COLOR["light"],
127
- "success_color": self.SUCCESS_COLOR["light"]
128
- }
129
- else:
130
- colors = {
131
- "bg_color": self.DARK_BG_COLOR,
132
- "fg_color": self.DARK_FG_COLOR,
133
- "card_bg_color": self.DARK_CARD_BG_COLOR,
134
- "sidebar_bg_color": self.DARK_SIDEBAR_BG_COLOR,
135
- "sidebar_fg_color": self.DARK_SIDEBAR_FG_COLOR,
136
- "sidebar_hover_color": self.DARK_SIDEBAR_HOVER_COLOR,
137
- "sidebar_active_color": self.DARK_SIDEBAR_ACTIVE_COLOR,
138
- "button_bg_color": self.DARK_BUTTON_BG_COLOR,
139
- "button_hover_color": self.DARK_BUTTON_HOVER_COLOR,
140
- "button_active_color": self.DARK_BUTTON_ACTIVE_COLOR,
141
- "input_bg_color": self.DARK_INPUT_BG_COLOR,
142
- "input_fg_color": self.DARK_INPUT_FG_COLOR,
143
- "border_color": self.DARK_BORDER_COLOR,
144
- "primary_color": self.PRIMARY_COLOR["dark"],
145
- "secondary_color": self.SECONDARY_COLOR["dark"],
146
- "accent_color": self.ACCENT_COLOR["dark"],
147
- "warning_color": self.WARNING_COLOR["dark"],
148
- "error_color": self.ERROR_COLOR["dark"],
149
- "success_color": self.SUCCESS_COLOR["dark"]
150
- }
151
-
152
- return colors.get(color_name, self.LIGHT_BG_COLOR)
153
-
154
- def get_font(self, font_type):
155
- """الحصول على خط معين"""
156
- return self.fonts.get(font_type, self.fonts["body"])
157
-
158
- def toggle_theme(self):
159
- """تبديل النمط بين الفاتح والداكن"""
160
- if self.current_theme == "light":
161
- self.current_theme = "dark"
162
- else:
163
- self.current_theme = "light"
164
-
165
- # تحديث النمط في الإعدادات
166
- self.config.set_theme(self.current_theme)
167
-
168
- # تحديث نمط customtkinter
169
- ctk.set_appearance_mode(self.current_theme)
170
-
171
- return self.current_theme
172
-
173
- def create_styled_frame(self, parent, **kwargs):
174
- """إنشاء إطار منسق"""
175
- default_kwargs = {
176
- "fg_color": self.get_color("bg_color"),
177
- "corner_radius": 10,
178
- "border_width": 0
179
- }
180
-
181
- # دمج الخصائص المخصصة مع الخصائص الافتراضية
182
- for key, value in kwargs.items():
183
- default_kwargs[key] = value
184
-
185
- return ctk.CTkFrame(parent, **default_kwargs)
186
-
187
- def create_styled_scrollable_frame(self, parent, **kwargs):
188
- """إنشاء إطار قابل للتمرير منسق"""
189
- default_kwargs = {
190
- "fg_color": self.get_color("bg_color"),
191
- "corner_radius": 10,
192
- "border_width": 0
193
- }
194
-
195
- # دمج الخصائص المخصصة مع الخصائص الافتراضية
196
- for key, value in kwargs.items():
197
- default_kwargs[key] = value
198
-
199
- return ctk.CTkScrollableFrame(parent, **default_kwargs)
200
-
201
- def create_styled_label(self, parent, text, **kwargs):
202
- """إنشاء تسمية منسقة"""
203
- default_kwargs = {
204
- "text": text,
205
- "font": self.get_font("body"),
206
- "text_color": self.get_color("fg_color")
207
- }
208
-
209
- # دمج الخصائص المخصصة مع الخصائص الافتراضية
210
- for key, value in kwargs.items():
211
- default_kwargs[key] = value
212
-
213
- return ctk.CTkLabel(parent, **default_kwargs)
214
-
215
- def create_styled_button(self, parent, text, **kwargs):
216
- """إنشاء زر منسق"""
217
- default_kwargs = {
218
- "text": text,
219
- "font": self.get_font("body"),
220
- "fg_color": self.get_color("button_bg_color"),
221
- "hover_color": self.get_color("button_hover_color"),
222
- "text_color": "white",
223
- "corner_radius": 8,
224
- "border_width": 0,
225
- "height": 36
226
- }
227
-
228
- # إضافة أيقونة إذا تم تحديدها
229
- if "icon" in kwargs:
230
- icon_name = kwargs.pop("icon")
231
- # هنا يمكن إضافة منطق لتحميل الأيقونة
232
-
233
- # دمج الخصائص المخصصة مع الخصائص الافتراضية
234
- for key, value in kwargs.items():
235
- default_kwargs[key] = value
236
-
237
- return ctk.CTkButton(parent, **default_kwargs)
238
-
239
- def create_styled_entry(self, parent, placeholder_text, **kwargs):
240
- """إنشاء حقل إدخال منسق"""
241
- default_kwargs = {
242
- "placeholder_text": placeholder_text,
243
- "font": self.get_font("body"),
244
- "fg_color": self.get_color("input_bg_color"),
245
- "text_color": self.get_color("input_fg_color"),
246
- "placeholder_text_color": self.get_color("border_color"),
247
- "corner_radius": 8,
248
- "border_width": 1,
249
- "border_color": self.get_color("border_color"),
250
- "height": 36
251
- }
252
-
253
- # دمج الخصائص المخصصة مع الخصائص الافتراضية
254
- for key, value in kwargs.items():
255
- default_kwargs[key] = value
256
-
257
- return ctk.CTkEntry(parent, **default_kwargs)
258
-
259
- def create_styled_textbox(self, parent, **kwargs):
260
- """إنشاء مربع نص منسق"""
261
- default_kwargs = {
262
- "font": self.get_font("body"),
263
- "fg_color": self.get_color("input_bg_color"),
264
- "text_color": self.get_color("input_fg_color"),
265
- "corner_radius": 8,
266
- "border_width": 1,
267
- "border_color": self.get_color("border_color")
268
- }
269
-
270
- # دمج الخصائص المخصصة مع الخصائص الافتراضية
271
- for key, value in kwargs.items():
272
- default_kwargs[key] = value
273
-
274
- return ctk.CTkTextbox(parent, **default_kwargs)
275
-
276
- def create_styled_combobox(self, parent, values, **kwargs):
277
- """إنشاء قائمة منسدلة منسقة"""
278
- default_kwargs = {
279
- "values": values,
280
- "font": self.get_font("body"),
281
- "fg_color": self.get_color("input_bg_color"),
282
- "text_color": self.get_color("input_fg_color"),
283
- "border_color": self.get_color("border_color"),
284
- "button_color": self.get_color("button_bg_color"),
285
- "button_hover_color": self.get_color("button_hover_color"),
286
- "dropdown_fg_color": self.get_color("card_bg_color"),
287
- "dropdown_text_color": self.get_color("fg_color"),
288
- "dropdown_hover_color": self.get_color("sidebar_hover_color"),
289
- "corner_radius": 8,
290
- "border_width": 1,
291
- "dropdown_font": self.get_font("body")
292
- }
293
-
294
- # دمج الخصائص المخصصة مع الخصائص الافتراضية
295
- for key, value in kwargs.items():
296
- default_kwargs[key] = value
297
-
298
- return ctk.CTkComboBox(parent, **default_kwargs)
299
-
300
- def create_styled_switch(self, parent, text, **kwargs):
301
- """إنشاء مفتاح تبديل منسق"""
302
- default_kwargs = {
303
- "text": text,
304
- "font": self.get_font("body"),
305
- "fg_color": self.get_color("border_color"),
306
- "progress_color": self.get_color("button_bg_color"),
307
- "button_color": "white",
308
- "button_hover_color": "white",
309
- "text_color": self.get_color("fg_color")
310
- }
311
-
312
- # دمج الخصائص المخصصة مع الخصائص الافتراضية
313
- for key, value in kwargs.items():
314
- default_kwargs[key] = value
315
-
316
- return ctk.CTkSwitch(parent, **default_kwargs)
317
-
318
- def create_styled_radio_button(self, parent, text, variable, value, **kwargs):
319
- """إنشاء زر راديو منسق"""
320
- default_kwargs = {
321
- "text": text,
322
- "font": self.get_font("body"),
323
- "fg_color": self.get_color("button_bg_color"),
324
- "border_color": self.get_color("border_color"),
325
- "hover_color": self.get_color("button_hover_color"),
326
- "text_color": self.get_color("fg_color"),
327
- "variable": variable,
328
- "value": value
329
- }
330
-
331
- # دمج الخصائص المخصصة مع الخصائص الافتراضية
332
- for key, value in kwargs.items():
333
- default_kwargs[key] = value
334
-
335
- return ctk.CTkRadioButton(parent, **default_kwargs)
336
-
337
- def create_styled_slider(self, parent, **kwargs):
338
- """إنشاء شريط تمرير منسق"""
339
- default_kwargs = {
340
- "fg_color": self.get_color("border_color"),
341
- "progress_color": self.get_color("button_bg_color"),
342
- "button_color": self.get_color("button_bg_color"),
343
- "button_hover_color": self.get_color("button_hover_color")
344
- }
345
-
346
- # دمج الخصائص المخصصة مع الخصائص الافتراضية
347
- for key, value in kwargs.items():
348
- default_kwargs[key] = value
349
-
350
- return ctk.CTkSlider(parent, **default_kwargs)
351
-
352
- def create_styled_tabview(self, parent, **kwargs):
353
- """إنشاء عرض تبويب منسق"""
354
- default_kwargs = {
355
- "fg_color": self.get_color("card_bg_color"),
356
- "segmented_button_fg_color": self.get_color("sidebar_bg_color"),
357
- "segmented_button_selected_color": self.get_color("button_bg_color"),
358
- "segmented_button_unselected_color": self.get_color("sidebar_bg_color"),
359
- "segmented_button_selected_hover_color": self.get_color("button_hover_color"),
360
- "segmented_button_unselected_hover_color": self.get_color("sidebar_hover_color"),
361
- "segmented_button_text_color": self.get_color("sidebar_fg_color"),
362
- "segmented_button_selected_text_color": "white",
363
- "text_color": self.get_color("fg_color"),
364
- "corner_radius": 10
365
- }
366
-
367
- # دمج الخصائص المخصصة مع الخصائص الافتراضية
368
- for key, value in kwargs.items():
369
- default_kwargs[key] = value
370
-
371
- return ctk.CTkTabview(parent, **default_kwargs)
372
-
373
- def create_styled_sidebar_button(self, parent, text, icon, command=None):
374
- """إنشاء زر الشريط الجانبي المنسق"""
375
- # إنشاء إطار للزر
376
- button_frame = ctk.CTkFrame(
377
- parent,
378
- fg_color="transparent",
379
- corner_radius=0
380
- )
381
-
382
- # إنشاء الزر
383
- button = ctk.CTkButton(
384
- button_frame,
385
- text=text,
386
- font=self.get_font("body"),
387
- fg_color="transparent",
388
- hover_color=self.get_color("sidebar_hover_color"),
389
- text_color=self.get_color("sidebar_fg_color"),
390
- anchor="w",
391
- corner_radius=0,
392
- border_width=0,
393
- height=40,
394
- command=command
395
- )
396
- button.pack(fill="x", padx=0, pady=0)
397
-
398
- return button_frame, button
399
-
400
- def create_styled_card(self, parent, title):
401
- """إنشاء بطاقة منسقة"""
402
- # إنشاء إطار البطاقة
403
- card = self.create_styled_frame(
404
- parent,
405
- fg_color=self.get_color("card_bg_color")
406
- )
407
-
408
- # إنشاء عنوان البطاقة
409
- title_label = self.create_styled_label(
410
- card,
411
- title,
412
- font=self.get_font("heading")
413
- )
414
- title_label.pack(anchor="w", padx=15, pady=(15, 5))
415
-
416
- # إنشاء خط فاصل
417
- separator = ctk.CTkFrame(
418
- card,
419
- height=1,
420
- fg_color=self.get_color("border_color")
421
- )
422
- separator.pack(fill="x", padx=15, pady=(5, 0))
423
-
424
- # إنشاء إطار المحتوى
425
- content_frame = self.create_styled_frame(
426
- card,
427
- fg_color="transparent"
428
- )
429
- content_frame.pack(fill="both", expand=True, padx=15, pady=15)
430
-
431
- return card, content_frame
432
-
433
- def create_styled_data_table(self, parent, columns, data):
434
- """إنشاء جدول بيانات منسق"""
435
- # إنشاء إطار الجدول
436
- table_frame = self.create_styled_frame(
437
- parent,
438
- fg_color="transparent"
439
- )
440
-
441
- # إنشاء إطار العناوين
442
- header_frame = self.create_styled_frame(
443
- table_frame,
444
- fg_color=self.get_color("sidebar_bg_color")
445
- )
446
- header_frame.pack(fill="x", padx=0, pady=(0, 1))
447
-
448
- # إنشاء عناوين الأعمدة
449
- for i, column in enumerate(columns):
450
- column_label = self.create_styled_label(
451
- header_frame,
452
- column,
453
- font=self.get_font("heading"),
454
- text_color=self.get_color("sidebar_fg_color")
455
- )
456
- column_label.grid(row=0, column=i, sticky="ew", padx=10, pady=10)
457
- header_frame.grid_columnconfigure(i, weight=1)
458
-
459
- # إنشاء إطار البيانات
460
- data_frame = self.create_styled_scrollable_frame(
461
- table_frame,
462
- fg_color="transparent"
463
- )
464
- data_frame.pack(fill="both", expand=True, padx=0, pady=0)
465
-
466
- # إنشاء صفوف البيانات
467
- for i, row in enumerate(data):
468
- row_frame = self.create_styled_frame(
469
- data_frame,
470
- fg_color=self.get_color("card_bg_color") if i % 2 == 0 else self.get_color("bg_color")
471
- )
472
- row_frame.pack(fill="x", padx=0, pady=(0, 1))
473
-
474
- for j, cell in enumerate(row):
475
- cell_label = self.create_styled_label(
476
- row_frame,
477
- cell,
478
- font=self.get_font("body")
479
- )
480
- cell_label.grid(row=0, column=j, sticky="ew", padx=10, pady=10)
481
- row_frame.grid_columnconfigure(j, weight=1)
482
-
483
- return table_frame, data_frame
484
-
485
- def create_styled_message_box(self, title, message, message_type="info"):
486
- """إنشاء مربع رسالة منسق"""
487
- # تحديد لون الرسالة بناءً على النوع
488
- if message_type == "error":
489
- color = self.get_color("error_color")
490
- elif message_type == "warning":
491
- color = self.get_color("warning_color")
492
- elif message_type == "success":
493
- color = self.get_color("success_color")
494
- else: # info
495
- color = self.get_color("primary_color")
496
-
497
- # إنشاء نافذة الرسالة
498
- message_window = ctk.CTkToplevel()
499
- message_window.title(title)
500
- message_window.geometry("400x200")
501
- message_window.resizable(False, False)
502
- message_window.grab_set() # جعل النافذة المنبثقة مركز الاهتمام
503
-
504
- # تطبيق النمط
505
- message_window.configure(fg_color=self.get_color("bg_color"))
506
-
507
- # إنشاء إطار الرسالة
508
- message_frame = self.create_styled_frame(
509
- message_window,
510
- fg_color=self.get_color("card_bg_color")
511
- )
512
- message_frame.pack(fill="both", expand=True, padx=20, pady=20)
513
-
514
- # إنشاء عنوان الرسالة
515
- title_label = self.create_styled_label(
516
- message_frame,
517
- title,
518
- font=self.get_font("heading"),
519
- text_color=color
520
- )
521
- title_label.pack(padx=20, pady=(20, 10))
522
-
523
- # إنشاء نص الرسالة
524
- message_label = self.create_styled_label(
525
- message_frame,
526
- message,
527
- font=self.get_font("body")
528
- )
529
- message_label.pack(padx=20, pady=(0, 20))
530
-
531
- # إنشاء زر موافق
532
- ok_button = self.create_styled_button(
533
- message_frame,
534
- "موافق",
535
- fg_color=color,
536
- hover_color=color,
537
- command=message_window.destroy
538
- )
539
- ok_button.pack(pady=(0, 20))
540
-
541
- return message_window