اختر النافذة المنبثقة المناسبة
النافذة المنبثقة تقاطع اللاعب. وقبل أن تختار واحدة، أجب عن سؤال واحد: هل يجب أن يجيب اللاعب قبل أن تمضي اللعبة؟ إن كان الجواب نعم، فاحجب. وإن كان لا، فلا تحجب أبدًا — فبطاقة توقف اللعبة لتنقل خبرًا لم يطلبه اللاعب هي أسرع طريقة لتجعله يغلق لعبتك.
- سؤال له جواب — شراء، حذف، مغادرة، كتابة فوق حفظ ←
GoDialogs.confirm(). أمر يجب الإقرار به ←alert(). واحد من خيارات قليلة ←choose(). - شاشة قائمة بذاتها — الإعدادات، صفحة الشخصية، غرض في المتجر ←
GoSurfaceفي وسط الشاشة. - قائمة طويلة أو صفحة إدارة — الحقيبة، البريد، الأصدقاء ←
GoSheetمن الأسفل على الهاتف، وGoDrawerمن الجانب على الشاشة العريضة. - شيء يخصّ ما ضُغط عليه للتو — إحصاءات غرض، وما يمكن فعله به ←
GoPopoverأوGoContextMenuبجانبه. - خبر تستطيع اللعبة أن تمضي معه — تمّ الحفظ، أُسقط غرض، وصلت دعوة ←
GoSnackbarأوGoNoticeأوGoPromptCard. وهذه لا تستولي على الشاشة أبدًا. - تعليم أدوات التحكم ←
GoCoachMark. أوامر الغشّ أثناء البناء ←GoConsole.
كل النوافذ المنبثقة في لمحة
| النافذة المنبثقة | توقف اللعبة | الرجوع / Escape | نقرة خارجها | استعملها لـ |
|---|---|---|---|---|
GoDialogs confirm · alert | نعم | يغلقها — confirm يجيب false، وalert يعود | تغلقها فقط مع dismiss_on_scrim | أسئلة تحتاج إلى جواب |
GoDialogs.choose | نعم | يغلقها — ويجيب -1 | تغلقها فقط مع dismiss_on_scrim | اختيار واحد من خيارات قليلة |
GoSurface | نعم | يطلب إغلاق العليا | تطلب الإغلاق مع dismiss_on_scrim | نوافذك أنت |
GoSheet | نعم | يغلق الورقة كلها | تغلقها | الحقيبة، قائمة متجر، البريد |
GoDrawer | نعم | زر الرجوع في Android فقط | تغلقه | قائمة جانبية على شاشة عريضة |
GoPopover | حتى تُغلق | يغلقها | تغلقها — ولا تمضي أبعد | تفاصيل الأغراض والمهارات |
قائمة GoCombobox | حتى تُغلق | يغلقها | تغلقها | قائمة اختيار فيها بحث |
GoContextMenu · القائمة المنسدلة · قائمة الاختيار | بحسب قائمة المحرّك | بحسب قائمة المحرّك | تغلقها | إجراءات، قوائم قصيرة |
GoSnackbar | لا | — | تصل إلى اللعبة | تمّ الحفظ · تراجع · أعد المحاولة |
GoPromptCard | لا | — | تصل إلى اللعبة | دعوة، طلب مقايضة |
GoNotice | أبدًا | — | تصل إلى اللعبة | سطر ثابت على HUD |
GoBanner | لا — فهي جزء من الصفحة | — | — | «أنت غير متصل. أعد المحاولة» |
GoCoachMark | بطاقتها فقط | ينهي الجولة | تصل إلى اللعبة | جولة التشغيل الأول |
GoConsole | لوحتها فقط | مفتاح Escape يغلقها | تصل إلى اللعبة | أوامر التنقيح |
على أي طبقة تُفتح كل واحدة، ولماذا بهذا الترتيب، تجده في الطبقات وزر الرجوع والإدخال.

GoDialogs
GoSurface
GoSheet
GoDrawer
GoPopover
GoContextMenu
GoSnackbar
GoPromptCard
GoCoachMark
GoConsoleكل صورة في هذه الصفحة هي اللعبة الصغيرة نفسها — الصحة والمانا أعلى اليسار، والعملات أعلى اليمين، وعصا توجيه وثلاث
خانات سريعة في الأسفل — بالنمط الجاهز default_dark، وفوقها نافذة منبثقة واحدة مفتوحة. النافذة
المنبثقة نفسها بالمظاهر الأربعة عشر كلها ←
تشريح النافذة المنبثقة
كل نافذة منبثقة حاجبة تقريبًا في gohud — مربعات الحوار والأوراق والبطاقات المنبثقة وقائمة المنتقي ونوافذك
أنت — هي عقدة واحدة: GoSurface. تعلّم أجزاءها مرة واحدة فتعرفها كلها.

| الجزء | ما هو | كيف تصل إليه |
|---|---|---|
| الطبقة | طبقة CanvasLayer التي تعيش عليها النافذة المنبثقة. ورقمها يقرّر ما الذي تغطيه. | من اختيارك في GoSurface؛ ومدمجة في البقية (الجدول) |
| الحجاب | الستار الممدود فوق كل ما خلفها. يلتقط النقرات التي تخطئ البطاقة. | scrim_transparent، dismiss_on_scrim، ولون scrim في السمة |
| البطاقة | النافذة نفسها — وجه اللوحة في السمة، مدوّرة أو مشطوفة أو مطروقة أو هلامية بحسب المظهر. | card، alpha |
| الرأس | زر رجوع اختياري، والعنوان (سطران على الأكثر، ثم «…»)، وزر الإغلاق. | set_title() · set_title_key() · set_back() · close_enabled · show_header |
| شريط الأدوات | صفّ ثابت تحت الرأس — حقل بحث، شرائح تصفية. مخفي حتى تستعمله. | toolbar |
| الجسم | الجزء المتمرّر. ضع المحتوى هنا. | body · scroll_body · clear() |
| سطر الحالة | سطر ثابت بين الجسم والتذييل — «فشل التحقّق من الاسم»، «جارٍ الحفظ…». | set_status_text() · set_status_key() · clear_status() |
| التذييل | أزرار ثابتة في الأسفل. مخفي حتى تستعمله. | footer |
toolbar وسطر الحالة وfooter؛ فهي تبقى في مكانها بينما يتمرّر الجسم.
مربعات حوار تنتظرها بـ await
GoDialogs يسأل وينتظر. عقدة واحدة وثلاثة أسئلة — ويعود الجواب على السطر نفسه، فيُقرأ الكود
بالترتيب الذي يعيشه اللاعب.
var dialogs := GoDialogs.new()
add_child(dialogs)
if await dialogs.confirm("Buy the starter pack?", "300 gems for a sword, a shield and 10 potions.",
"Buy", "Not now"):
buy_starter_pack()

confirm()
confirm(…, true) — لا رجعة فيه
alert()
choose()
ActionLayout.HORIZONTALالأسئلة الثلاثة
confirm(title, body, ok_text := "", cancel_text := "", extra := "",
args := {}, destructive := false) -> bool
alert(title, body, ok_text := "", extra := "", args := {}) # انتظره بـ await
choose(title, options: Array, cancel_text := "", translate := false) -> int
confirm_key(…) · alert_key(…) # بمفاتيح ترجمة
| الاستدعاء | يعيد | استعمله لـ |
|---|---|---|
confirm() | true أو false | نعم أو لا — شراء، حذف، مغادرة، كتابة فوق حفظ. |
alert() | لا شيء — انتظره بـ await | ما يجب أن يراه اللاعب: مكافأة، انقطاع الاتصال. |
choose() | فهرس الخيار، أو -1 | واحد من خيارات قليلة. والخيار نصّ String أو {text, icon, danger, subtitle}. |
confirm_key() · alert_key() | كما سبق | الشيء نفسه بمفاتيح ترجمة — فتتبع الكلماتُ تغييرَ اللغة ومربع الحوار مفتوح. |
تسميات الأزرار الفارغة تعود إلى كلمات الأداة نفسها (confirm وcancel في GoConfig.text_keys).
وextra يُضاف إلى المتن في سطر جديد. وargs يملأ {placeholders} في العنوان
والمتن: confirm("Buy {item}?", "It costs {price} gold.", "Buy", "", "", {"item": name, "price": 300}).
لكل مخرج جواب
| اللاعب… | confirm | alert | choose |
|---|---|---|---|
| يضغط موافق / خيارًا | true | يعود | فهرس الخيار |
| يضغط إلغاء | false | — | -1 |
| يضغط × أو Escape أو زر الرجوع في Android | false | يعود | -1 |
ينقر الحجاب (فقط مع dismiss_on_scrim) | false | يعود | -1 |
تغادر عقدة GoDialogs الشجرة | false | يعود | -1 |
لذا فالكود بعد await يعمل دائمًا — لا يبقى سؤال معلّقًا بلا جواب أبدًا، حتى حين يتغيّر المشهد من تحت مربع الحوار.
الإجراءات التي لا رجعة فيها
مرّر destructive = true لما لا يمكن التراجع عنه. فيصير زر الموافقة الزرَّ المصمت
Tone.DANGER_SOLID — أبيض على أحمر في كل مظهر، حيث كان نص الخطر المصبوغ سيضطر إلى الدكانة حتى يقارب
الأسود في السمة الفاتحة ليبقى مقروءًا. وتُعاد النبرة عند كل استدعاء، لأن النافذة يُعاد استعمالها.
if await dialogs.confirm("Delete this save?", "Slot 2 — Aria, level 12. This cannot be undone.",
"Delete", "Keep it", "", {}, true):
delete_save(2)
ترتيب الأزرار
action_layout | ما الذي يفعله |
|---|---|
VERTICAL (الافتراضي) | أزرار مرصوصة فوق بعضها بالعرض الكامل. آمن مع كل لغة — فلا تنضغط تسمية ألمانية أو روسية طويلة أبدًا. |
HORIZONTAL | صفّ واحد، لكل زر نصف العرض. |
AUTO | صفّ واحد فقط حين تتّسع التسميتان في نصف البطاقة على سطر واحد، وإلا رُصّت. ويُعاد القرار عند تغيير اللغة أو الحجم. |
action_gap هو المسافة بين الأزرار، وbody_gap المسافة فوقها — اجعلها أوسع من
مسافة الأزرار ليُقرأ السؤال والاختيار جزأين. ولمربع حوار واحد فقط، استدعِ
set_next_action_layout() قبل فتحه. وزرّ التنبيه الوحيد يأخذ العرض الكامل دائمًا.
واحد في كل مرة
استدعاء confirm() ثانٍ بينما الأول مفتوح يعيد false فورًا — فلا يتكدّس مربع حوار فوق آخر
صدفةً. شغّل queue_when_busy فينتظر دوره بدلًا من ذلك؛ أما alert() فينتظر دائمًا.
وqueue_limit (8) يحدّ طول الطابور، وعند الفيض يُجاب أقدم طلب بـ false.
وpending() يعدّ الطلبات المنتظرة، وclear_pending() يجيبها كلها بـ false.
أما choose() فلا يدخل الطابور أبدًا: يعيد -1 حين يكون مربع حوار مفتوحًا أصلًا.
الهاتف وسطح المكتب
choose() يُفتح ورقةً من الأسفل على Android وiOS — حيث الإبهام — وبطاقةً في
الوسط على سطح المكتب. والتأكيد محدود بـ max_width (420dp) وموسَّط. اضبط layer_index
وmax_width وسائر الخصائص المصدَّرة قبل add_child؛ فهي تُطبَّق حين تدخل العقدة الشجرة.
var picked := await dialogs.choose("Sort the bag by", [
{"text": "Newest first", "icon": GoIconSet.CLOCK},
{"text": "Rarity", "icon": GoIconSet.STAR},
{"text": "Drop everything", "icon": GoIconSet.TRASH, "danger": true}])
if picked >= 0:
sort_bag(picked)
GoSurface — نافذة خاصة بك
حين تكون النافذة المنبثقة أكثر من سؤال — إعدادات، صفحة شخصية، غرض للشراء — ابنها على
GoSurface. فالمنطقة الآمنة ولوحة المفاتيح والصفوف الثابتة والتمرير وزر الرجوع والتركيز وتغيير الحجم كلها منجزة.
var layer := CanvasLayer.new()
layer.layer = 50
add_child(layer)
var window := GoSurface.new()
window.set_title("Settings")
window.close_requested.connect(layer.queue_free)
window.body.add_child(GoStyle.toggle("Music", false))
window.body.add_child(GoStyle.slider(0.0, 1.0, 0.05))
var row := GoStyle.row()
row.add_child(GoStyle.button("Cancel", window.request_close))
row.add_child(GoStyle.button("Save", save_and_close, GoStyle.Tone.PRIMARY))
window.footer.add_child(row)
window.footer.visible = true
layer.add_child(window)
close_requested. وإخفاء
النافذة أو تحريرها مهمّة الشاشة المالكة — فهي وحدها تعرف إن كان «الإغلاق» يعني الحفظ أم التجاهل أم السؤال أولًا.
ثلاثة مواضع

CENTER — تأكيدات، إعدادات
BOTTOM — قوائم، صفحات إدارة
ANCHOR — بجانب عنصر تحكم
GoDatePicker في نافذة CENTERANCHOR يحتاج anchor_control. تذهب البطاقة إلى يمينه إن اتّسع لها anchor_min_width،
وإلا إلى الجهة الأوسع، وإلا داخل الشاشة، وتُفتح إلى الأعلى حين يكون المتّسع فوقه أكبر. وهي تتبع المرساة
المتحرّكة في كل إطار. وanchor_width (320) وanchor_max_height (520) يحدّدان حجمها.
إلى أي حدّ تكبر
| المقياس | القاعدة | تغيّره بـ |
|---|---|---|
| المتّسع | المنطقة الآمنة، ناقص لوحة المفاتيح، ناقص هامش الشاشة (16dp، ولا يزيد على 10% من الضلع الأقصر). | — |
| العرض | 94% من المتّسع في الوضع العمودي، و72% في الأفقي، و480dp على الأكثر. | max_width · GoConfig.surface_width_ratio_* |
| الارتفاع | بطول المحتوى (fit_content)، حتى 68% من المتّسع، وسقفه 72%. والبطاقة الموسَّطة غير القابلة لتغيير الحجم قد تكبر حتى 94% تفاديًا للتمرير. | height_ratio · max_height_ratio · max_height |
| الكثافة | تصير مكثّفة حين يُضبط compact، أو يقلّ ارتفاع الشاشة عن 420dp (هاتف على جنبه)، أو لا يتّسع المحتوى: حشوة أقل، وفجوات أصغر، وعنوان أصغر. وهي تقيس الحالتين وتُبقي الأرحب الذي يتّسع — بلا اهتزاز. | compact |
| تغيير الحجم | مع resizable يصير العنوان مقبضًا: اسحبه بين 30% والسقف. وheight_changed(ratio) يبلّغ بالنتيجة. | resizable |
النسبة التي تتجاوز السقف تُقصّ إليه، مع تحذير واحد في بناء التنقيح. ولوحة المفاتيح تدفع البطاقة إلى الأعلى وتمرّر الحقل المركَّز إلى مجال الرؤية؛ والمنطقة الآمنة تبعدها عن النتوء وشريط الإيماءات على Android وiOS.
الخصائص
| الخاصية | الافتراضي | ما الذي تفعله |
|---|---|---|
placement | CENTER | CENTER أو BOTTOM أو ANCHOR |
dismiss_on_scrim | GoConfig.dismiss_on_scrim (false) | نقرة على الحجاب تطلب الإغلاق. أما سحبٌ بدأ داخل البطاقة فلا. |
scrim_transparent | false | تُبقي اللعبة ظاهرة — ويظلّ الحجاب يلتقط النقرات الخارجية. |
close_enabled | true | تُظهر × وتسمح لـ Escape وزر الرجوع بطلب الإغلاق. |
show_header · scroll_body · resizable | true · true · false | صفّ الرأس، والجسم المتمرّر، ومقبض السحب. |
fit_content · compact | true · false | الحجم على قدر المحتوى؛ والبدء مكثّفًا. |
fade_in | GoConfig.surface_fade_in (false) | تُظهر البطاقة بتلاشٍ تدريجي عند الفتح، وفورًا مع reduce_motion. |
alpha | -1 (قيمة السمة) | عتامة وجه البطاقة، كنسبة. الوجه وحده يبهت — والنص أبدًا. |
initial_focus | لا شيء | عنصر التحكم الذي يُركَّز عليه عند الفتح. |
add_child: scrim_transparent وshow_header وresizable و
scroll_body تُطبَّق حين تدخل النافذة الشجرة. أما dismiss_on_scrim وclose_enabled و
fade_in وinitial_focus فتُقرأ حيّة.
الإشارات والاستدعاءات
| الاسم | ما هو |
|---|---|
close_requested | × أو Escape أو زر الرجوع في Android أو نقرة على الحجاب — وrequest_close(). ولا تطلقها إلا النافذة العليا. |
back_requested · set_back(action) | زر الرجوع في الرأس، لنافذة ذات صفحات. وCallable فارغ يخفيه. |
height_changed(ratio) | بعد سحب المقبض. |
is_top() · GoSurface.is_any_open() | هل هذه هي النافذة التي تأخذ زر الرجوع — وهل ثمّة نافذة مفتوحة أصلًا. |
relayout() | أعد التخطيط الآن. وتغيير خاصية من خصائص الحجم يفعل ذلك عنك أصلًا. |
الأوراق والأدراج
القائمة التي تحتاج إلى متّسع تصعد من الأسفل على هاتف يُمسك قائمًا — حيث الإبهام — وتدخل من الجانب على لوح أو سطح مكتب، حيث كانت الورقة ستغطّي اللعبة.

GoSheet
GoDrawer · LEFT
GoDrawer · RIGHTGoSheet — صفحات من الأسفل
var sheet := GoSheet.new()
add_child(sheet)
func show_bag(items: Array) -> void:
sheet.open("Bag")
var search := GoStyle.line_edit("Search the bag…")
search.text_changed.connect(filter_bag)
sheet.toolbar().add_child(search)
sheet.toolbar().visible = true
for item in items:
sheet.body.add_child(GoStyle.list_button(GoIconSet.BOX, item.name, show_item.bind(item),
Color.TRANSPARENT, item.description, false, GoIconSet.CHEVRON_RIGHT))
sheet.add_footer(GoStyle.button("Close", sheet.close, GoStyle.Tone.PRIMARY))
- هي
CanvasLayer(الطبقة 10) تحملGoSurfaceمن نوعBOTTOMقابلة لتغيير الحجم — فتجلس فوق HUD، ويستطيع اللاعب سحبها لتطول. open(title)يبدأ صفحة جديدة: يفرّغ الجسم وشريط الأدوات وزر الرجوع، ويحرّر ما أضافهadd_footer(). استدعه مجددًا لتعرض صفحة أخرى في الورقة نفسها؛ وset_back()يُظهر زر رجوع لطريق العودة. وopen_key()يأخذ مفتاح ترجمة.close()يخفيها — ولا يحرّرها، فيكونopen()التالي فوريًا. وclosedوpage_changedيخبرانك متى.height_ratio(0.6) هو الارتفاع الذي تُفتح عليه؛ وmax_height_ratioيرفع السقف؛ وdismissable(true) يغلقها بنقرة على الحجاب.
set_back() — فزرّ الرجوع الظاهر على الشاشة
وحده يعود صفحةً إلى الوراء. وإن أردت أن يعود زر الرجوع خطوة، فتعامل مع close_requested على sheet.surface بنفسك.
GoDrawer — من الجانب
var drawer := GoDrawer.new()
drawer.side = GoDrawer.Side.LEFT
drawer.follow_text_direction = true # جهة البداية: اليسار، أو اليمين في العربية
add_child(drawer)
drawer.body.add_child(GoNavBar.drawer_list([{"icon": GoIconSet.HOME, "text": "Town"},
{"icon": GoIconSet.MAP, "text": "World map"}], 0, go_to))
drawer.open("Menu")
- الطبقة 80. عرضه 42% من الشاشة (
width_ratio)، بينmin_width(320dp) وmax_width(420dp) — فهو على الهاتف يغطّي معظم الشاشة، ولهذا كانت الورقة الخيار الأفضل هناك. - اللوحة تبلغ حافة الشاشة؛ والمحتوى وحده يتراجع إلى داخل المنطقة الآمنة، فلا يقصّ ركنٌ مدوّر الصفَّ الأول أبدًا.
LEFTتعني يسار الشاشة حتى في العربية. شغّلfollow_text_directionحين يكون المقصود «جهة البداية»؛ وeffective_side()يخبرك أين ذهب.open(title)يحتفظ بالجسم — املأه مرة واحدة. وset_title("")يخفي الرأس. وmotion_seconds(0.2) يُدخله انزلاقًا؛ وreduce_motionيجعله فوريًا.
drawer.close() من ربط مفاتيحك أنت — ولاحظ أن GoSurface.is_any_open() لا يحسب الدرج؛
فاسأل drawer.is_open().
بطاقات وقوائم بجانب عنصر التحكم
ما ضغطه اللاعب للتو يستحقّ جوابًا بجانب إصبعه مباشرة، لا في وسط الشاشة.

GoPopover
GoContextMenu
GoStyle.dropdown()
GoStyle.select()
GoComboboxGoPopover — بطاقة على ما ضُغط عليه
slot.pressed.connect(func() -> void:
var card := GoStyle.item_card({"icon": GoIconSet.POTION, "title": "Health potion",
"subtitle": "Heals 50 HP · 12 left"}, false)
GoPopover.open(slot, card, {"width": 280}))
سطح من نوع ANCHOR وقد وُصلت له الطبقةُ والمرساةُ والتفكيكُ سلفًا — تلك الأسطر العشرة التي تكتبها كل لعبة
مرارًا وتكرارًا. واحدة في كل مرة: فتح الثانية يغلق الأولى، لأن البطاقات المكدّسة تدفن الشاشة فلا يعرف أحد
أي بطاقة تخصّ أي خانة. والحجاب شفاف — فبطاقة فُتحت لمقارنة العتاد يجب ألّا تُعتم العتاد — لكنه يظلّ يلتقط
أول نقرة خارجية، فتُغلق البطاقة ولا تمضي النقرة أبعد.
| الخيار | الافتراضي | ما الذي يفعله |
|---|---|---|
title | "" | رأس فيه ×. والفارغ يعني بلا رأس. |
width · max_height | 320 · 520 | حجم البطاقة. |
dismissable | true | النقرة الخارجية تغلقها. |
compact · alpha · translate | false · -1 · false | تباعد مكثّف، وعتامة الوجه، والعنوان مفتاحَ ترجمة. |
layer | 95 | طبقة CanvasLayer التي تُفتح عليها. |
GoPopover.close() وGoPopover.is_open() ساكنتان. وopen() يعيد السطح — أو
null حين لا تكون المرساة في الشجرة، فتحقّق من ذلك قبل await shown.close_requested.
dismissable = false وبلا عنوان، لا شيء على الشاشة يغلقها — إلا Escape أو زر الرجوع أو استدعاؤك أنت.
GoContextMenu — الضغط المطوَّل والنقر الأيمن
var menu := [
{"text": "Use", "icon": GoIconSet.POTION, "action": use},
{"separator": true},
{"text": "Drop", "icon": GoIconSet.TRASH, "action": drop, "danger": true}]
GoContextMenu.attach(slot, menu)
var more := GoStyle.icon_button(GoIconSet.MORE, Callable(), -1, &"more")
more.pressed.connect(func() -> void: GoContextMenu.open_at(more, menu))
- النقر الأيمن يفتحها فورًا. وإصبع يبقى مضغوطًا نصف ثانية (
HOLD_SECONDS) يفتحها؛ والتحرّك أكثر من 12dp يلغيها — فتمرير قائمة لا يُظهر قائمة سياق أبدًا. - العنصر هو
{text, action, icon, disabled, checked, separator, danger, translate}. ومرّرCallableبدل المصفوفة حين تعتمد المدخلات على ما ضُغط عليه؛ فيُستدعى في كل مرة تُفتح فيها القائمة. dangerيضع «⚠ » قبل النص — فقائمة المحرّك لا تستطيع أن تلوّن إلا عناصرها كلها دفعة واحدة.- هي
PopupMenuالخاصة بالمحرّك، يكسوهاGoStyle.style_popup(). ولا تُحسب سطحًا مفتوحًا.
⋯ ظاهر
(open_at()، كما في الأعلى)، أو علّمه مرة واحدة بعلامة إرشادية.
القوائم المنسدلة وقوائم الاختيار والزر المنقسم
var sort := GoStyle.dropdown("Sort", ["Highest score", "Most wins", {"text": "Friends only", "disabled": true}],
func(index: int) -> void: sort_board(index))
var quality := GoStyle.select(["Low", "Medium", "High", "Ultra"], "Quality")
quality.item_selected.connect(func(index: int) -> void: settings.quality = index)
var send := GoSplitButton.make("Send", send_now, ["Send later", "Save as draft"])
الثلاثة كلها تفتح قائمة المحرّك المنبثقة: dropdown() هو MenuButton ينفّذ إجراءً،
وselect() هو OptionButton يحتفظ بقيمة، وGoSplitButton إجراء رئيسي مع قائمة على
سهمه (chosen(index)). والقوائم تبقى معتمة تمامًا عن قصد — فالقائمة المعروضة في نافذة نظام تشغيل خاصة بها
تحوّل البكسلات نصف الشفافة إلى سوداء.
GoCombobox — قائمة فيها بحث
var friend := GoCombobox.make(friend_names, -1, "Find a friend")
friend.picked.connect(func(index: int) -> void: invite(friend_names[index]))
عند الضغط عليه يفتح قائمة مثبّتة على الطبقة 96 بحجاب شفاف. وابتداءً من search_threshold (8) عناصر
يظهر حقل بحث ويأخذ التركيز؛ وهو يطابق في أي موضع من النص أو التلميح، متجاهلًا حالة الأحرف، والنتيجة الفارغة
تقول ذلك صراحة. وlist_width (0 = عرض الزر، و180dp على الأقل) يحدّد حجم القائمة.
نوافذ منبثقة لا توقف اللعبة أبدًا
أخبار يستطيع اللاعب قراءتها وهو يلعب. لا حجاب لأيّ منها؛ والنقرة في أي مكان غير البطاقة نفسها تذهب إلى اللعبة.

GoSnackbar
GoNotice
GoPromptCard
GoStyle.tooltip_node()GoSnackbar — رسالة مع زر تراجع
var snack := GoSnackbar.new()
add_child(snack)
if await snack.post({"text": "Dropped {name}", "args": {"name": item.name}, "icon": GoIconSet.TRASH,
"actions": ["Undo"], "seconds": 5.0}) == 0:
restore(item)
مفتاح post() | ما الذي يفعله |
|---|---|
text · title · args · translate | الرسالة، وسطر عريض اختياري، و{placeholders}، ومفاتيح الترجمة. |
tone · icon | لون التمييز (GoTheme.SUCCESS وWARNING…) وأيقونة. |
actions · closable | أزرار — نصوص String أو {text, action} — و×. |
seconds | مدة بقائه. السالب: notice_duration_ms من السمة. 0: حتى يُصرف — فأعطه زرًا عندئذٍ. |
post() يعيد فهرس الزر المضغوط، أو -1 حين تنتهي المهلة أو يُصرف. والمنشورات تصطفّ
(queue_limit 4، ويُسقط الأقدم مع -1)، والنص نفسه إذا نُشر مجددًا وهو ظاهر لا يفعل سوى تجديد مؤقّته.
ويجلس في الأسفل (أو الأعلى، عبر placement)، فوق المنطقة الآمنة ولوحة المفاتيح، على الطبقة 90 — مقروءًا
فوق الدرج. ومع tap_to_dismiss (مشغّل) تغلقه النقرة على بطاقة بلا أزرار؛ أما النقرة خارج البطاقة فتصل
إلى اللعبة دائمًا. وshow_text() وshow_key() هما الصيغتان ذواتا السطر الواحد.
GoNotice — سطر على HUD
var notice := GoNotice.new()
hud_corner.add_child(notice)
notice.show_text("Game saved", GoTheme.SUCCESS)
notice.custom_minimum_size.x = notice.preferred_width(340)
لوحة بسيطة تضعها بنفسك — في GoHudAnchor، أو في ركن، أو في أي مكان. لا تأخذ لمسًا ولا تركيزًا،
فالضغط عبرها يصل إلى الزر الذي تحتها، والرسالة الجديدة تحلّ محلّ القديمة. أعطها عرضًا:
preferred_width(limit) يعيد العرض الطبيعي للنص القصير ويلفّ النص الطويل داخل limit.
وset_content() يعرض أي عنصر تحكم بدل النص.
GoPromptCard — سؤال يحتمل الانتظار
var spot := GoHudAnchor.new()
spot.spot = GoHudAnchor.Spot.TOP_CENTER
spot.reserve_space = false
spot.avoid_peers = true # انزل تحت أشرطة الصحة بدل أن تغطّيها
hud.add_child(spot)
var invite := GoPromptCard.new()
spot.add_child(invite)
invite.set_icon(GoIconSet.USERS, Color.TRANSPARENT, true)
invite.set_title("Party invite from Ann")
invite.set_subtitle("Dragon's Lair · 3 / 4 members")
invite.set_actions([{"text": "Accept", "action": accept, "primary": true},
{"text": "Decline", "action": invite.hide}])
invite.fit_width(340)
invite.show()
get_tree().create_timer(15.0).timeout.connect(invite.hide)
- تبدأ مخفية — استدعِ
show(). وليس لها مؤقّت خاص؛ فأضف واحدًا إن كان للسؤال أجل. - أزرارها لا تغلقها — الإجراءات هي التي تقرّر. و× (
set_closable(true)) يطلقclosed. fit_width(width)يضبط العرض ويتنبّأ بالارتفاع من الخط، فلا يقفز شيء مُخطَّط بالنسبة إليها بعد إطار.- وجهها يتبع
hud_alpha— فهي جزء من HUD، لا نافذة.
GoBanner والتلميحات
GoBanner.make("You're offline.", [{"text": "Retry", "action": reconnect}], GoIconSet.WARNING) تجلس في الصفحة
نفسها، فوق المحتوى، ولا تنتهي مهلتها أبدًا؛ والزر يصرفها ما لم يكن فيه "keep": true.
وGoStyle.tooltip_node(text) هو ما تعيده من _make_custom_tooltip() — المحرّك يرسم اللوح
(TooltipPanel)، وgohud يرسم النص ملفوفًا بعد 260dp. والتلميحات للفأرة؛ فلا تخبّئ خلف تلميح شيئًا يحتاجه اللاعب.
الجولات ووحدة التحكّم

GoCoachMark
GoConsoleGoCoachMark — جولة على عناصر التحكم الحقيقية
var tour := GoCoachMark.new()
tour.keep_clear = [top_bar]
tour_layer.add_child(tour)
tour.finished.connect(func(completed: bool) -> void: save.tutorial_done = true)
tour.start([{"target": bag_button, "title": "Bag", "body": "Everything you pick up lands here."},
{"target": map_button, "title": "Map", "body": "Tap to open the full map."}])
- حلقة حول عنصر التحكم الحقيقي وبطاقة بجانبه. الضغط على الهدف ينتقل بالجولة (إشارة
pressedالخاصة به، أو"signal"في الخطوة)؛ وزرّا التالي والتخطّي على البطاقة. والهدف المخفي يُتخطّى. - البطاقة تبتعد عن وسط الشاشة (
avoid_center_band)، وعن مراسي HUD، وعنkeep_clear. - ما دامت أي
GoSurfaceمفتوحة تختفي الجولة وتنتظر. وزر الرجوع أو Escape ينهيها بـfinished(false). - ليست لها طبقة خاصة — أضفها أخيرًا، أو على طبقة فوق HUD.
GoConsole — أوامر الغشّ أثناء البناء
var console := GoConsole.new()
add_child(console)
console.register("give", "give <item> <count>", func(args: PackedStringArray) -> String:
return "gave %s x%s" % [args[0], args[1]] if args.size() >= 2 else "give <item> <count>")
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed(&"dev_console"): console.toggle()
الطبقة 200 — فوق كل شيء، فتستطيع أن تنقّح فوق مربع حوار — وتظلّ تعمل والشجرة متوقفة مؤقتًا. ولوحة أوامر تقترح الأوامر وأنت تكتب؛ والسهمان أعلى وأسفل يتنقّلان في السجلّ؛ وEscape يغلقها. ولا مفتاح مدمجًا لفتحها: اربط مفتاحك أنت.
debug_only (مشغّل) يحجبها في بناء الإصدار — open() وrun() كلاهما. فأوامر الغشّ
في يد لاعب تنهي اقتصاد اللعبة في اليوم الأول.
الطبقات وزر الرجوع والإدخال
ثلاث قواعد تقرّر ما يستطيع اللاعب لمسه بينما شيء ما مفتوح: ما الذي في الأعلى، ومن يملك زر الرجوع، ومن يأخذ النقرة.
ما الذي في الأعلى
| الطبقة | ما الذي يجلس فيها | تُضبط بـ |
|---|---|---|
| 5 | HUD الخاص بك (من اختيارك) | — |
| 10 | GoSheet | CanvasLayer.layer |
| ~50 | نوافذ GoSurface الخاصة بك، وقائمة الإيقاف المؤقت | طبقة CanvasLayer الخاصة بك |
| 80 | GoDrawer | CanvasLayer.layer |
| 90 | GoSnackbar | layer_index |
| 95 | GoPopover | الخيار "layer" |
| 96 | قائمة GoCombobox | — |
| 100 | GoDialogs | layer_index |
| 200 | GoConsole | layer_index |
الترتيب مقصود: شريط الإشعار يخبر بما حدث للتو، فيُقرأ فوق الدرج؛ والبطاقة المنبثقة تخصّ ما ضُغط للتو، فتجلس فوقه؛ ومربع الحوار يطرح سؤالًا ويغطّي الاثنين؛ ووحدة التحكّم تغطّي كل شيء، لأنها ما تفتحه حين يفسد كل ما عداها.
من يملك زر الرجوع
- النافذة العليا وحدها تجيب. من بين الأسطح المفتوحة، تأخذ التي على أعلى طبقة (ثم الأحدث في الشجرة)
مفتاح Escape وإلغاء ذراع التحكم (
ui_cancel) وزر الرجوع في Android ونقرات الحجاب. والنوافذ المكدّسة تُغلق واحدة واحدة، لا معًا أبدًا. - زر الرجوع في Android يُعالَج بعد إطار واحد، فلا تستطيع ضغطة واحدة أن تغلق نافذتين أبدًا.
- ما دام شيء يملك زر الرجوع مفتوحًا، لا يُنهي زر الرجوع في Android التطبيق (
GoBackPolicyيعدّ المالكين ويعيدquit_on_go_backبعد آخرهم). ونافذتك المنبثقة الخاصة التي تأخذ زر الرجوع يجب أن تستدعيGoBackPolicy.acquire()وrelease()— وفي_exit_treeأيضًا. - الدرج وجولة العلامات الإرشادية والنموذج تتنحّى ما دام سطح مفتوحًا — فزر الرجوع يذهب إلى السطح أولًا.
GoConfig.close_on_back(مشغّل) هو المفتاح الخاص بالأسطح.
من يأخذ النقرة
- السطح يغطّي الشاشة كلها ويوقف الإدخال — والحجاب الشفاف كذلك. لا يُضغط شيء على طبقة أدنى ما دام مفتوحًا؛ أما الطبقات التي فوقه (شريط الإشعار) فتظلّ تُضغط.
- عجلة الفأرة وإيماءات القرص تتوقّف عند النافذة أيضًا: فالتمرير إلى ما بعد نهاية القائمة لا يمرّر اللعبة أبدًا.
- مدخلات اللعب التي لا تمرّ عبر عناصر التحكم —
_unhandled_inputللحركة، وسحب الكاميرا — يجب أن تتوقف:if GoSurface.is_any_open(): return. وهذا يشمل مربعات الحوار والأوراق والبطاقات المنبثقة والمنتقي؛ أما الدرج فاسألهis_open()على حدة. - شريط الإشعار والإشعار وبطاقة السؤال والعلامة الإرشادية لا تأخذ الإدخال إلا على بطاقتها؛ وفي كل مكان آخر تأخذه اللعبة.
التركيز
النافذة التي تُفتح بالمؤشّر لا تركّز على شيء — فلا تومض حلقة عند اللمس. وإن فُتحت من لوحة المفاتيح أو ذراع التحكم،
أخذ زر الإغلاق (أو initial_focus) التركيز. ويبقى التركيز داخل النافذة ما دامت مفتوحة، ويعود إلى عنصر التحكم
الذي كان يحمله حين تُغلق. ومربعات الحوار تركّز على زر الموافقة في كل مرة.
إيقاف اللعبة مؤقتًا
إيقاف الشجرة مؤقتًا يوقف النوافذ المنبثقة أيضًا — ووحدة التحكّم وحدها تواصل العمل. ولقائمة إيقاف مؤقت، أعطِ طبقتها
process_mode = PROCESS_MODE_ALWAYS؛ فتظلّ النافذة وأزرارها وزر الرجوع تعمل واللعبة متوقفة.
النافذة المنبثقة نفسها بكل مظهر
التأكيد من أعلى هذه الصفحة، فوق اللعبة نفسها، ولم يتغيّر سوى النمط الجاهز. الكود متطابق — والسمة والمظهر والأيقونات تتكفّل بالباقي.

default_dark
default_light
scifi_dark
scifi_light
medieval_dark
medieval_light
material_light جديد
material_dark جديد
kids_light جديد
kids_dark جديد
comic_light جديد
comic_dark جديد
arcade_light جديد
arcade_dark جديدما الذي يغيّره كل مظهر
| المظهر | النافذة | رأسها وأزرارها |
|---|---|---|
| الافتراضي | مدوّرة (18dp)، بظلّ ناعم، معتمة بنسبة 80% فوق اللعبة | عنوان بسيط و×؛ والأزرار الأساسية ترتفع ثم تغوص |
| الخيال العلمي | زوايا مقطوعة بحافة نيون وتوهّج، والحافة مصبوغة بلون التمييز | علامات تركيز على شكل أقواس |
| العصور الوسطى | إطار مطروق — حديد وجلد، أو رقّ — بمسامير وزخارف أركان | عناوين بخط Cinzel |
| Material 3 | زوايا 28dp، وحشوة 24dp، ومعتمة تمامًا | عنوان رئيسي 24sp بخط Roboto؛ وأزرار حبة بلوح 40dp داخل مساحة لمس 48dp |
| الأطفال | بطاقة حلوى هلامية بظلّ ناعم، معتمة تمامًا | شريط عنوان مشمس (بلون النعناع ليلًا)، وزر إغلاق مستدير كالحلوى، وأزرار تنضغط كالهلام عند الضغط |
| القصص المصوّرة | حدّ حبري عريض وظلّ حادّ، معتمة تمامًا | لافتة عنوان صفراء، وزر إغلاق مستدير محبَّر، وأزرار يختفي ظلّها عند الضغط |
| الأركيد | لوح سميك — إطار ملوّن حول تجويف فاتح — معتم تمامًا | لافتة عنوان ذهبية بعنوان أبيض محدّد بالحبر، ومفتاح إغلاق أحمر مستدير، ومفاتيح ملوّنة تقفز عند الضغط |
كسوة النافذة المنبثقة من المظهر
المظهر يقرّر الأجزاء التي لا تبلغها السمة. وهذه الخطافات هي التي تستدعيها النوافذ المنبثقة — تجاوزها في صنف مشتقّ من
GoSkin خاص بك؛ وهي افتراضيًا لا تفعل شيئًا.
| الخطّاف | ما الذي يكسوه |
|---|---|
title_plate_box() · title_plate_ink() · title_plate_min_size() | لوح خلف عنوان النافذة. يتوسّطه العنوان ويصغر، حتى الحجم الأدنى (15)، ليبقى على سطر واحد. |
dress_close_button(button) | زر × في النافذة — مظهر الأطفال يجعله حلوى مستديرة، ومظهر القصص المصوّرة قرصًا محبَّرًا، ومظهر الأركيد مفتاحًا أحمر مستديرًا. |
dress_title(label) | تسمية عنوان النافذة — مظهر الأركيد يحدّد عنوانها الأبيض بالحبر. |
press_feedback(control) | يعمل لحظة يحطّ إصبع على زر صنعه gohud — مظهر الأطفال يجعله ينضغط كالهلام، ومظهر الأركيد يجعله يقفز. |
floating_box() · notice_box() · drawer_box() · banner_box() · overlay_box() | وجوه بطاقات السؤال وبطاقات الإرشاد، وأشرطة الإشعار والإشعارات، والدرج، واللافتات، ووحدة التحكّم. |
coach_ring_box() · draw_coach_pointer() | حلقة الجولة ومؤشّرها. |
إلى أي حدّ تشفّ
كل نوع من النوافذ المنبثقة يتبع عتامته الخاصة، فتبقى بطاقة HUD خفيفة بينما يبقى مربع الحوار مصمتًا: النوافذ والأوراق
ومربعات الحوار والبطاقات المنبثقة والمنتقي تتبع panel_alpha؛ والدرج وبطاقة الإرشاد card_alpha؛
وبطاقات السؤال ووحدة التحكّم hud_alpha؛ وأشرطة الإشعار والإشعارات notice_alpha؛ والقوائم popup_alpha.
أما مظهرا Material والأطفال فيجعلانها كلها معتمة، وكذلك مظهر القصص المصوّرة باستثناء بطاقات السؤال ووحدة التحكّم بعتامة 92%، ومظهر الأركيد كذلك باستثناء هذين بعتامة 94%. تجاوز نوعًا واحدًا بـ GoConfig.container_alpha_overrides، أو كلها بـ
container_alpha (نسبة — 0.95)، أو نافذة واحدة بخاصية alpha الخاصة بها. الوجه وحده يبهت؛
والنص لا يشفّ أبدًا. العتامة بالتفصيل ←
إعدادات تشكّل كل نافذة منبثقة
حقول GoConfig (GoUi.config). بعضها يُنسخ حين تُنشأ النافذة، فاضبطها
قبل بناء الواجهة — أو استدعِ GoUi.refresh() بعد تغييرها.
| الحقل | الافتراضي | ما الذي يفعله |
|---|---|---|
surface_max_width · surface_max_height | 480 · 700 | أقصى ما تبلغه النافذة. |
surface_height_ratio · surface_max_height_ratio | 0.68 · 0.72 | الارتفاع المعتاد والسقف (وهو حدّ السحب أيضًا). |
surface_fit_max_height_ratio | 0.94 | إلى أي حدّ تكبر البطاقة الموسَّطة المحجَّمة على قدر محتواها قبل أن تتمرّر. |
surface_width_ratio_portrait · …_landscape | 0.94 · 0.72 | العرض كنسبة من المتّسع. |
dismiss_on_scrim | false | نقرة الحجاب تغلق النوافذ ومربعات الحوار. يُنسخ حين تُنشأ النافذة. |
surface_fade_in · fade_seconds | false · 0.14 | إظهار النوافذ بتلاشٍ تدريجي، وسرعته. |
close_on_back | true | Escape وui_cancel وزر الرجوع في Android تغلق النافذة العليا. |
close_button_visual | 36 | الحجم الذي يبدو عليه × — وتبقى مساحة لمسه 48dp. |
suppress_pointer_focus_ring | true | لا حلقة تركيز حين تُفتح النافذة باللمس أو الفأرة. |
container_alpha · container_alpha_overrides | -1 · {} | عتامة كل الوجوه، أو لكل نوع (GoTheme.BOX_*). |
reduce_motion | false | لا تلاشي ولا انزلاق ولا نبض ولا انضغاط. |
min_touch_size | 48 | ارتفاع أزرار بطاقة السؤال والعلامة الإرشادية. |
respect_safe_area | true | إبعاد النوافذ عن النتوء وشريط الإيماءات. |
text_keys · text_overrides | — | كلمات الأداة نفسها: close وback وconfirm وcancel وnext وdone وskip وsearch وempty… |
sound_cues · الاهتزاز اللمسي | — | ما يشغّله GoFeedback عند الفتح والإغلاق والتأكيد والإلغاء والنقر. |
وصفات
انسخ، والصق، وغيّر الكلمات. كل استدعاء هنا مُتحقَّق منه مقابل الشيفرة المصدرية.
شراء يذكر السعر
func buy(item_name: String, price: int) -> void:
if await dialogs.confirm("Buy {item}?", "It costs {price} gold.", "Buy", "", "",
{"item": item_name, "price": price}):
purchase(item_name)
نافذة إعدادات بزر حفظ ثابت
func open_settings() -> void:
var layer := CanvasLayer.new()
layer.layer = 50
add_child(layer)
var window := GoSurface.new()
window.set_title("Settings")
window.dismiss_on_scrim = true
window.close_requested.connect(layer.queue_free)
window.body.add_child(GoStyle.section("Sound", false))
window.body.add_child(GoStyle.toggle("Music", false))
window.body.add_child(GoStyle.slider(0.0, 1.0, 0.05))
var row := GoStyle.row()
row.add_child(GoStyle.button("Cancel", window.request_close))
row.add_child(GoStyle.button("Save", func() -> void:
save_settings()
layer.queue_free(), GoStyle.Tone.PRIMARY))
window.footer.add_child(row)
window.footer.visible = true
layer.add_child(window)
نموذج يقول ما الخطأ
var field := GoField.make("Name", GoStyle.line_edit(), "3–12 letters")
window.body.add_child(field)
create_button.pressed.connect(func() -> void:
if name_is_taken():
field.set_error("That name is taken")
window.set_status_text("Name check failed", GoTheme.DANGER)
else:
window.clear_status()
create_character())
تاريخ في ورقة
sheet.open("Delivery date")
var picker := GoDatePicker.make({"year": 2026, "month": 10, "day": 14}, func(date: Dictionary) -> void:
delivery = date
sheet.close())
picker.min_date = GoDatePicker.today()
sheet.body.add_child(picker)
قائمة إيقاف مؤقت
func pause() -> void:
get_tree().paused = true
var layer := CanvasLayer.new()
layer.layer = 50
layer.process_mode = Node.PROCESS_MODE_ALWAYS # تواصل العمل واللعبة متوقفة مؤقتًا
add_child(layer)
var menu := GoSurface.new()
menu.set_title("Paused")
menu.close_requested.connect(func() -> void:
get_tree().paused = false
layer.queue_free())
menu.body.add_child(GoStyle.button("Resume", menu.request_close, GoStyle.Tone.PRIMARY))
menu.body.add_child(GoStyle.button("Settings", open_settings))
menu.body.add_child(GoStyle.button("Quit to title", quit_to_title, GoStyle.Tone.DANGER))
layer.add_child(menu)
لعب ينتظر النوافذ المنبثقة
func _unhandled_input(event: InputEvent) -> void:
if GoSurface.is_any_open() or drawer.is_open():
return
handle_gameplay(event)
مزالق
GoSurfaceلا تحرّر نفسها أبدًا. اربطclose_requested، وإلا فلن يفعل × شيئًا.- الخيارات المضبوطة بعد
add_child—scrim_transparentوshow_headerوresizableوscroll_body، وlayer_indexوmax_widthفيGoDialogs— لا تُطبَّق. - استدعاء
confirm()الثاني يعيدfalseفورًا. شغّلqueue_when_busyإن كان سؤالان قد يلتقيان. - Enter يؤكّد. زر الموافقة يحمل التركيز، في مربعات الحوار التي لا رجعة فيها أيضًا.
- زر الرجوع على الورقة يغلق الورقة، لا الصفحة الفرعية.
- Escape لا يغلق الدرج، و
is_any_open()لا يراه. - البطاقة المنبثقة أو قائمة المنتقي تحجب اللعبة حتى تُغلق، حتى مع حجاب شفاف — والبطاقة المنبثقة التي فيها
dismissable = falseوبلا عنوان ليس على الشاشة ما يغلقها. - بطاقة السؤال تبدأ مخفية وليست لها مهلة.
- شريط الإشعار الذي فيه
seconds: 0وبلا زر لا يرحل أبدًا. وهو يلتقط النقرات على بطاقته افتراضيًا. - ضغطة مطوّلة لا يعرف بها أحد ميزةٌ لا يستعملها أحد. أظهر
⋯أيضًا. - الشجرة المتوقفة مؤقتًا توقف نافذتك المنبثقة. استعمل
PROCESS_MODE_ALWAYSعلى طبقتها. - الإشعار الذي بلا عرض ينكمش إلى أضيق ما يكون — استعمل
preferred_width(). - لا تسأل في شريط إشعار، ولا تُخبر في مربع حوار. فالسؤال يختفي حين يُتجاهل؛ والخبر لا ينبغي أن يوقف اللعبة.