// lity_editor.c - Lity3D Editor (Win32 Unicode, 50+ built-in languages) #include #include #include #include #include #include #include #define IDC_TREE 1001 #define IDC_EDIT 1002 #define IDC_CONSOLE 1003 #define IDM_NEW 2001 #define IDM_OPEN 2002 #define IDM_SAVE 2003 #define IDM_RUN 2004 #define IDM_BUILD 2005 #define IDM_PACKAGE 2006 #define IDM_ABOUT 2007 #define IDM_LANG_BASE 3000 #define NUM_KEYS 20 #define NUM_LANGS 50 static HWND g_hwnd, g_tree, g_edit, g_console; static WCHAR g_current_file[MAX_PATH] = L""; static WCHAR g_engine_dir[MAX_PATH] = L""; // Key names static const char* g_keys[NUM_KEYS] = { "title","file","build","scene","help","lang", "new","open","save","exit","run","compile", "package","explorer","output","ready","about","ok","kill","build_first" }; // lang_code, display_name, translations[NUM_KEYS] static struct { const char* code; const char* name; const WCHAR* trans[NUM_KEYS]; } g_langs[NUM_LANGS] = { {"en","English",{L"Lity3D Editor",L"File",L"Build",L"Scene",L"Help",L"Language",L"New",L"Open",L"Save",L"Exit",L"Run",L"Build Engine",L"Package EXE",L"Explorer",L"Output",L"Ready",L"About",L"OK",L"Process killed",L"Build first"}}, {"zh","中文",{L"Lity3D 编辑器",L"文件",L"构建",L"场景",L"帮助",L"语言",L"新建",L"打开",L"保存",L"退出",L"运行游戏",L"编译引擎",L"打包 EXE",L"资源管理器",L"输出",L"就绪",L"关于",L"确定",L"进程已终止",L"请先编译引擎"}}, {"ja","日本語",{L"Lity3D エディタ",L"ファイル",L"ビルド",L"シーン",L"ヘルプ",L"言語",L"新規",L"開く",L"保存",L"終了",L"ゲーム実行",L"エンジンビルド",L"EXE出力",L"エクスプローラ",L"出力",L"準備完了",L"について",L"OK",L"停止済み",L"先にビルド"}}, {"ko","한국어",{L"Lity3D 편집기",L"파일",L"빌드",L"씬",L"도움말",L"언어",L"새로 만들기",L"열기",L"저장",L"종료",L"게임 실행",L"엔진 빌드",L"EXE 패키징",L"탐색기",L"출력",L"준비",L"정보",L"확인",L"중지됨",L"먼저 빌드"}}, {"es","Español",{L"Lity3D Editor",L"Archivo",L"Compilar",L"Escena",L"Ayuda",L"Idioma",L"Nuevo",L"Abrir",L"Guardar",L"Salir",L"Ejecutar",L"Compilar motor",L"Empaquetar",L"Explorador",L"Salida",L"Listo",L"Acerca de",L"OK",L"Detenido",L"Compilar primero"}}, {"fr","Français",{L"Lity3D Éditeur",L"Fichier",L"Construire",L"Scène",L"Aide",L"Langue",L"Nouveau",L"Ouvrir",L"Enregistrer",L"Quitter",L"Exécuter",L"Compiler",L"Package",L"Explorateur",L"Sortie",L"Prêt",L"À propos",L"OK",L"Arrêté",L"Compiler d'abord"}}, {"de","Deutsch",{L"Lity3D Editor",L"Datei",L"Erstellen",L"Szene",L"Hilfe",L"Sprache",L"Neu",L"Öffnen",L"Speichern",L"Beenden",L"Spiel starten",L"Engine erstellen",L"EXE paketieren",L"Explorer",L"Ausgabe",L"Bereit",L"Über",L"OK",L"Gestoppt",L"Erst bauen"}}, {"ru","Русский",{L"Lity3D Редактор",L"Файл",L"Сборка",L"Сцена",L"Справка",L"Язык",L"Новый",L"Открыть",L"Сохранить",L"Выход",L"Запуск",L"Собрать",L"Упаковать",L"Проводник",L"Вывод",L"Готово",L"О программе",L"OK",L"Остановлено",L"Сначала собрать"}}, {"pt","Português",{L"Lity3D Editor",L"Arquivo",L"Compilar",L"Cena",L"Ajuda",L"Idioma",L"Novo",L"Abrir",L"Salvar",L"Sair",L"Executar",L"Compilar engine",L"Empacotar",L"Explorador",L"Saída",L"Pronto",L"Sobre",L"OK",L"Parado",L"Compilar primeiro"}}, {"it","Italiano",{L"Lity3D Editor",L"File",L"Compila",L"Scena",L"Aiuto",L"Lingua",L"Nuovo",L"Apri",L"Salva",L"Esci",L"Esegui",L"Compila engine",L"Pacchetta",L"Esplora",L"Output",L"Pronto",L"Info",L"OK",L"Fermato",L"Compila prima"}}, {"tr","Türkçe",{L"Lity3D Editör",L"Dosya",L"Derle",L"Sahne",L"Yardım",L"Dil",L"Yeni",L"Aç",L"Kaydet",L"Çıkış",L"Çalıştır",L"Motoru derle",L"Paketle",L"Gezgin",L"Çıktı",L"Hazır",L"Hakkında",L"Tamam",L"Durduruldu",L"Önce derle"}}, {"ar","العربية",{L"Lity3D محرر",L"ملف",L"بناء",L"مشهد",L"مساعدة",L"لغة",L"جديد",L"فتح",L"حفظ",L"خروج",L"تشغيل",L"بناء المحرك",L"تغليف",L"مستكشف",L"مخرجات",L"جاهز",L"حول",L"موافق",L"تم الإيقاف",L"ابنِ أولاً"}}, {"hi","हिन्दी",{L"Lity3D संपादक",L"फ़ाइल",L"बिल्ड",L"दृश्य",L"सहायता",L"भाषा",L"नया",L"खोलें",L"सहेजें",L"बाहर",L"चलाएं",L"इंजन बिल्ड",L"EXE पैकेज",L"एक्सप्लोरर",L"आउटपुट",L"तैयार",L"के बारे में",L"ठीक है",L"बंद",L"पहले बिल्ड"}}, {"th","ภาษาไทย",{L"Lity3D ตัวแก้ไข",L"ไฟล์",L"สร้าง",L"ฉาก",L"ช่วยเหลือ",L"ภาษา",L"ใหม่",L"เปิด",L"บันทึก",L"ออก",L"รันเกม",L"สร้างเอนจิ้น",L"打包 EXE",L"ตัวสำรวจ",L"ผลลัพธ์",L"พร้อม",L"เกี่ยวกับ",L"ตกลง",L"หยุดแล้ว",L"สร้างก่อน"}}, {"vi","Tiếng Việt",{L"Lity3D Trình soạn",L"Tệp",L"Xây dựng",L"Cảnh",L"Trợ giúp",L"Ngôn ngữ",L"Mới",L"Mở",L"Lưu",L"Thoát",L"Chạy game",L"Build engine",L"Gói EXE",L"Duyệt",L"Đầu ra",L"Sẵn sàng",L"Giới thiệu",L"OK",L"Đã dừng",L"Build trước"}}, {"id","Bahasa",{L"Lity3D Editor",L"Berkas",L"Build",L"Sken",L"Bantuan",L"Bahasa",L"Baru",L"Buka",L"Simpan",L"Keluar",L"Jalankan",L"Build Engine",L"Paket EXE",L"Penjelajah",L"Output",L"Siap",L"Tentang",L"OK",L"Berhenti",L"Build dulu"}}, {"pl","Polski",{L"Lity3D Edytor",L"Plik",L"Kompiluj",L"Scena",L"Pomoc",L"Język",L"Nowy",L"Otwórz",L"Zapisz",L"Wyjście",L"Uruchom",L"Kompiluj engine",L"Pakietuj",L"Eksplorator",L"Wyjście",L"Gotowy",L"O programie",L"OK",L"Zatrzymano",L"Najpierw kompiluj"}}, {"nl","Nederlands",{L"Lity3D Editor",L"Bestand",L"Bouwen",L"Scène",L"Help",L"Taal",L"Nieuw",L"Open",L"Opslaan",L"Afsluiten",L"Uitvoeren",L"Engine bouwen",L"Pakket",L"Verkenner",L"Uitvoer",L"Gereed",L"Over",L"OK",L"Gestopt",L"Eerst bouwen"}}, {"uk","Українська",{L"Lity3D Редактор",L"Файл",L"Збірка",L"Сцена",L"Довідка",L"Мова",L"Новий",L"Відкрити",L"Зберегти",L"Вихід",L"Запуск",L"Зібрати",L"Упакувати",L"Провідник",L"Вивід",L"Готово",L"Про програму",L"OK",L"Зупинено",L"Спочатку зібрати"}}, {"cs","Čeština",{L"Lity3D Editor",L"Soubor",L"Sestavit",L"Scéna",L"Nápověda",L"Jazyk",L"Nový",L"Otevřít",L"Uložit",L"Konec",L"Spustit",L"Sestavit engine",L"Zabalit",L"Průzkumník",L"Výstup",L"Připraveno",L"O",L"OK",L"Zastaveno",L"Nejdřív sestavit"}}, {"ro","Română",{L"Lity3D Editor",L"Fișier",L"Compilă",L"Scenă",L"Ajutor",L"Limbă",L"Nou",L"Deschide",L"Salvează",L"Ieșire",L"Rulează",L"Compilează",L"Pachet",L"Explorator",L"Ieșire",L"Gata",L"Despre",L"OK",L"Oprit",L"Compilează prima"}}, {"sv","Svenska",{L"Lity3D Redigerare",L"Fil",L"Bygg",L"Scen",L"Hjälp",L"Språk",L"Ny",L"Öppna",L"Spara",L"Avsluta",L"Kör",L"Bygg engine",L"Paketera",L"Utforskare",L"Utdata",L"Redo",L"Om",L"OK",L"Stoppad",L"Bygg först"}}, {"fi","Suomi",{L"Lity3D Editor",L"Tiedosto",L"Käännä",L"Sken",L"Ohje",L"Kieli",L"Uusi",L"Avaa",L"Tallenna",L"Lopeta",L"Käynnistä",L"Käännä engine",L"Paketoi",L"Selain",L"Tuloste",L"Valmis",L"Tietoja",L"OK",L"Pysäytetty",L"Käännä ensin"}}, {"da","Dansk",{L"Lity3D Editor",L"Fil",L"Byg",L"Scene",L"Hjælp",L"Sprog",L"Ny",L"Åbn",L"Gem",L"Afslut",L"Kør",L"Byg engine",L"Pakke",L"Stifinder",L"Output",L"Klar",L"Om",L"OK",L"Stoppet",L"Byg først"}}, {"no","Norsk",{L"Lity3D Editor",L"Fil",L"Bygg",L"Scene",L"Hjelp",L"Språk",L"Ny",L"Åpne",L"Lagre",L"Avslutt",L"Kjør",L"Bygg engine",L"Pakke",L"Utforsker",L"Utdata",L"Klar",L"Om",L"OK",L"Stoppet",L"Bygg først"}}, {"el","Ελληνικά",{L"Lity3D Επεξεργαστής",L"Αρχείο",L"Κατασκευή",L"Σκηνή",L"Βοήθεια",L"Γλώσσα",L"Νέο",L"Άνοιγμα",L"Αποθήκευση",L"Έξοδος",L"Εκτέλεση",L"Κατασκευή",L"Πακέτο",L"Ανιχνευτής",L"Έξοδος",L"Έτοιμο",L"Σχετικά",L"OK",L"Σταμάτησε",L"Κατασκευή πρώτα"}}, {"he","עברית",{L"Lity3D עורך",L"קובץ",L"בנייה",L"סצנה",L"עזרה",L"שפה",L"חדש",L"פתח",L"שמור",L"יציאה",L"הרץ",L"בנה מנוע",L"ארוז",L"סייר",L"פלט",L"מוכן",L"אודות",L"אישור",L"נעצר",L"בנה קודם"}}, {"ms","Bahasa Melayu",{L"Lity3D Editor",L"Fail",L"Bina",L"Adegan",L"Bantuan",L"Bahasa",L"Baharu",L"Buka",L"Simpan",L"Keluar",L"Jalankan",L"Bina engine",L"Pakej",L"Peneroka",L"Output",L"Sedia",L"Tentang",L"OK",L"Dihentikan",L"Bina dahulu"}}, {"hu","Magyar",{L"Lity3D Szerkesztő",L"Fájl",L"Fordítás",L"Jelenet",L"Súgó",L"Nyelv",L"Új",L"Megnyitás",L"Mentés",L"Kilépés",L"Futtatás",L"Fordítás",L"Csomagolás",L"Fájlkezelő",L"Kimenet",L"Kész",L"Névjegy",L"OK",L"Leállítva",L"Előbb fordíts"}}, {"sk","Slovenčina",{L"Lity3D Editor",L"Súbor",L"Kompilácia",L"Scéna",L"Pomoc",L"Jazyk",L"Nový",L"Otvoriť",L"Uložiť",L"Ukončiť",L"Spustiť",L"Skompilovať",L"Balenie",L"Prieskumník",L"Výstup",L"Pripravené",L"O",L"OK",L"Zastavené",L"Skompilovať prvú"}}, {"bg","Български",{L"Lity3D Редактор",L"Файл",L"Компилация",L"Сцена",L"Помощ",L"Език",L"Нов",L"Отвори",L"Запази",L"Изход",L"Стартирай",L"Компилирай",L"Опаковай",L"Проводник",L"Изход",L"Готово",L"Относно",L"OK",L"Спряно",L"Първо компилирай"}}, {"hr","Hrvatski",{L"Lity3D Urednik",L"Datoteka",L"Izgradi",L"Scena",L"Pomoć",L"Jezik",L"Novo",L"Otvori",L"Spremi",L"Izlaz",L"Pokreni",L"Izgradi",L"Pakiraj",L"Istraživač",L"Izlaz",L"Spreman",L"O",L"OK",L"Zaustavljeno",L"Prvo izgradi"}}, {"sr","Српски",{L"Lity3D Уредник",L"Датотека",L"Изградња",L"Сцена",L"Помоћ",L"Језик",L"Ново",L"Отвори",L"Сачувај",L"Излаз",L"Покрени",L"Изгради",L"Пакуј",L"Истраживач",L"Излаз",L"Спреман",L"О",L"OK",L"Заустављено",L"Прво изгради"}}, {"sl","Slovenščina",{L"Lity3D Urejevalnik",L"Datoteka",L"Izgradi",L"Scena",L"Pomoč",L"Jezik",L"Novo",L"Odpri",L"Shrani",L"Izhod",L"Zaženi",L"Izgradi",L"Pakiraj",L"Raziskovalec",L"Izhod",L"Pripravljeno",L"O",L"OK",L"Ustavljeno",L"Najprej izgradi"}}, {"lt","Lietuvių",{L"Lity3D Redaktorius",L"Failas",L"Kompiliuoti",L"Scena",L"Pagalba",L"Kalba",L"Naujas",L"Atidaryti",L"Išsaugoti",L"Išeiti",L"Paleisti",L"Kompiliuoti",L"Pakuot",L"Naršyklė",L"Išvestis",L"Pasirengęs",L"Apie",L"OK",L"Sustabdyta",L"Kompiliuoti pirmiau"}}, {"lv","Latviešu",{L"Lity3D Redaktors",L"Fails",L"Kompilēt",L"Aina",L"Palīdzība",L"Valoda",L"Jauns",L"Atvērt",L"Saglabāt",L"Izeja",L"Palaist",L"Kompilēt",L"Pakēt",L"Pārlūks",L"Izeja",L"Gatavs",L"Par",L"OK",L"Aizturēts",L"Vispirums kompilēt"}}, {"et","Eesti",{L"Lity3D Redaktor",L"Fail",L"Kompileeri",L"Stseen",L"Abi",L"Keel",L"Uus",L"Ava",L"Salvesta",L"Välju",L"Käivita",L"Kompileeri",L"Pakendi",L"Eksploorija",L"Väljund",L"Valmis",L"Teave",L"OK",L"Peatatud",L"Esmalt kompileeri"}}, {"fa","فارسی",{L"Lity3D ویرایشگر",L"پرونده",L"ساخت",L"صحنه",L"راهنما",L"زبان",L"جدید",L"باز کردن",L"ذخیره",L"خروج",L"اجرا",L"ساخت موتور",L"بسته بندی",L"کاوشگر",L"خروجی",L"آماده",L"درباره",L"تأیید",L"متوقف شد",L"اول بساز"}}, {"bn","বাংলা",{L"Lity3D সম্পাদক",L"ফাইল",L"বিল্ড",L"দৃশ্য",L"সাহায্য",L"ভাষা",L"নতুন",L"খুলুন",L"সংরক্ষণ",L"বের হোন",L"চালান",L"ইঞ্জিন বিল্ড",L"EXE প্যাকেজ",L"এক্সপ্লোরার",L"আউটপুট",L"প্রস্তুত",L"সম্পর্কে",L"ঠিক আছে",L"বন্ধ",L"প্রথমে বিল্ড"}}, {"sw","Kiswahili",{L"Lity3D Mhariri",L"Faili",L"Jenga",L"Onyesho",L"Msaada",L"Lugha",L"Mpya",L"Fungua",L"Hifadhi",L"Ondoka",L"Endesha",L"Jenga injini",L"Pakiti",L"Vinara",L"Matokeo",L"Iko tayari",L"Kuhusu",L"Sawa",L"Imesimamishwa",L"Jenga kwanza"}}, {"ta","தமிழ்",{L"Lity3D திருத்தி",L"கோப்பு",L"உருவாக்கு",L"காட்சி",L"உதவி",L"மொழி",L"புதிய",L"திற",L"சேமி",L"வெளியேறு",L"இயக்கு",L"இயந்திரம் உருவாக்கு",L"EXE பேக்கேஜ்",L"ஆராய்ச்சியாளர்",L"வெளியீடு",L"தயார்",L"பற்றி",L"சரி",L"நிறுத்தப்பட்டது",L"முதலில் உருவாக்கு"}}, {"ml","മലയാളം",{L"Lity3D എഡിറ്റർ",L"ഫയൽ",L"ബിൽഡ്",L"രംഗം",L"സഹായം",L"ഭാഷ",L"പുതിയ",L"തുറക്കുക",L"സേവ് ചെയ്യുക",L"പുറത്തുപോകുക",L"റൺ ചെയ്യുക",L"എഞ്ചിൻ ബിൽഡ്",L"EXE പാക്കേജ്",L"എക്സ്പ്ലോറർ",L"ഔട്ട്പുട്ട്",L"തയ്യാർ",L"കുറിച്ച്",L"ശരി",L"നിർത്തി",L"ആദ്യം ബിൽഡ്"}}, {"te","తెలుగు",{L"Lity3D ఎడిటర్",L"ఫైల్",L"బిల్డ్",L"దృశ్యం",L"సహాయం",L"భాష",L"కొత్త",L"తెరవండి",L"సేవ్",L"నిష్క్రమించండి",L"రన్",L"ఇంజిన్ బిల్డ్",L"EXE ప్యాకేజ్",L"ఎక్స్‌ప్లోరర్",L"అవుట్‌పుట్",L"సిద్ధం",L"గురించి",L"సరే",L"ఆపబడింది",L"మొదట బిల్డ్"}}, {"ur","اردو",{L"Lity3D ایڈیٹر",L"فائل",L"بلڈ",L"منظر",L"مدد",L"زبان",L"نیا",L"کھولیں",L"محفوظ",L"باہر",L"چلائیں",L"اینجن بلڈ",L"EXE پیکج",L"ایکسپلورر",L"آؤٹ پٹ",L"تیار",L"بارے میں",L"ٹھیک ہے",L"روک دیا",L"پہلے بلڈ"}}, {"tl","Tagalog",{L"Lity3D Editor",L"File",L"Build",L"Scene",L"Tulong",L"Wika",L"Bago",L"Buksan",L"I-save",L"Lumabas",L"I-run",L"Build engine",L"Package",L"Explorer",L"Output",L"Handa",L"Tungkol",L"OK",L"Stopped",L"Build muna"}}, }; static int g_lang_count = NUM_LANGS; static int g_cur = 0; static const WCHAR* T(int k) { if (k < NUM_KEYS && g_langs[g_cur].trans[k]) return g_langs[g_cur].trans[k]; return L"?"; } static int detect_lang(void) { WCHAR buf[10]; if (GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, buf, 10)) { char abuf[16]; WideCharToMultiByte(CP_UTF8, 0, buf, -1, abuf, 16, NULL, NULL); for (int i = 0; i < g_lang_count; i++) if (!_stricmp(g_langs[i].code, abuf)) return i; } return 0; } static void populate_tree(void) { TreeView_DeleteAllItems(g_tree); TVINSERTSTRUCTW tvi = {0}; tvi.hParent = TVI_ROOT; tvi.hInsertAfter = TVI_LAST; tvi.item.mask = TVIF_TEXT; tvi.item.pszText = L"lity3d"; HTREEITEM root = TreeView_InsertItem(g_tree, &tvi); WIN32_FIND_DATAW fd; WCHAR pat[MAX_PATH]; wsprintfW(pat, L"%s\\*", g_engine_dir); HANDLE hF = FindFirstFileW(pat, &fd); if (hF == INVALID_HANDLE_VALUE) return; do { if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) continue; if (!wcscmp(fd.cFileName,L".")||!wcscmp(fd.cFileName,L"..")) continue; if (!wcscmp(fd.cFileName,L".git")||!wcscmp(fd.cFileName,L"build")||!wcscmp(fd.cFileName,L"target")) continue; tvi.hParent = root; tvi.item.pszText = fd.cFileName; HTREEITEM d = TreeView_InsertItem(g_tree, &tvi); WCHAR sub[MAX_PATH]; wsprintfW(sub, L"%s\\%s\\*", g_engine_dir, fd.cFileName); WIN32_FIND_DATAW fd2; HANDLE h2 = FindFirstFileW(sub, &fd2); if (h2 != INVALID_HANDLE_VALUE) { do { if (fd2.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue; tvi.hParent = d; tvi.item.pszText = fd2.cFileName; TreeView_InsertItem(g_tree, &tvi); } while (FindNextFileW(h2, &fd2)); FindClose(h2); } } while (FindNextFileW(hF, &fd)); FindClose(hF); } static void open_file_at(WCHAR* path) { HANDLE hf = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (hf == INVALID_HANDLE_VALUE) return; DWORD sz = GetFileSize(hf, NULL); char* buf = malloc(sz + 1); DWORD rd; ReadFile(hf, buf, sz, &rd, NULL); buf[sz] = '\0'; CloseHandle(hf); SetWindowTextA(g_edit, buf); free(buf); wcscpy(g_current_file, path); } static void open_file_dialog(void) { WCHAR file[MAX_PATH] = L""; OPENFILENAMEW of = {sizeof(of)}; of.lpstrFilter = L"All\0*.*\0Python\0*.py\0C\0*.c;*.h\0"; of.lpstrFile = file; of.nMaxFile = MAX_PATH; of.Flags = OFN_FILEMUSTEXIST; if (GetOpenFileNameW(&of)) open_file_at(file); } static void save_file(void) { if (!g_current_file[0]) { open_file_dialog(); return; } int len = GetWindowTextLengthA(g_edit); char* buf = malloc(len + 1); GetWindowTextA(g_edit, buf, len + 1); HANDLE hf = CreateFileW(g_current_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); if (hf != INVALID_HANDLE_VALUE) { DWORD wr; WriteFile(hf, buf, len, &wr, NULL); CloseHandle(hf); } free(buf); } static void console_msg(const char* msg) { int len = GetWindowTextLengthA(g_console); SendMessageA(g_console, EM_SETSEL, len, len); SendMessageA(g_console, EM_REPLACESEL, FALSE, (LPARAM)msg); } static void rebuild_lang_menu(void) { HMENU hBar = GetMenu(g_hwnd); HMENU hOld = GetSubMenu(hBar, 3); HMENU hLang = CreatePopupMenu(); for (int i = 0; i < g_lang_count; i++) { WCHAR label[192]; wsprintfW(label, L"%hs (%hs)", g_langs[i].name, g_langs[i].code); UINT flags = (i == g_cur) ? (MF_STRING | MF_CHECKED) : MF_STRING; AppendMenuW(hLang, flags, IDM_LANG_BASE + i, label); } RemoveMenu(hBar, 3, MF_BYPOSITION); InsertMenuW(hBar, 3, MF_BYPOSITION | MF_POPUP, (UINT_PTR)hLang, L"语言"); if (hOld) DestroyMenu(hOld); DrawMenuBar(g_hwnd); } static LRESULT CALLBACK WP(HWND h, UINT m, WPARAM w, LPARAM l) { switch (m) { case WM_COMMAND: { int id = LOWORD(w); if (id == IDM_NEW) { SetWindowTextA(g_edit, ""); g_current_file[0] = 0; } else if (id == IDM_OPEN) open_file_dialog(); else if (id == IDM_SAVE) save_file(); else if (id == IDM_RUN) { WCHAR p[MAX_PATH]; wsprintfW(p, L"%s\\build\\lity.exe", g_engine_dir); if (GetFileAttributesW(p) == INVALID_FILE_ATTRIBUTES) { console_msg("[!] Build first\n"); return 0; } ShellExecuteW(NULL, L"open", p, NULL, g_engine_dir, SW_SHOWNORMAL); } else if (id == IDM_BUILD) { WCHAR cmd[MAX_PATH*2]; wsprintfW(cmd, L"/c set PATH=C:\\mingw64\\bin;%%PATH%%&& cd /d %s\\build && cmake --build . -j4", g_engine_dir); ShellExecuteW(NULL, L"open", L"cmd.exe", cmd, NULL, SW_SHOWNORMAL); } else if (id == IDM_ABOUT) MessageBoxW(h, L"Lity3D Engine v1.0", L"About", MB_OK); else if (id >= IDM_LANG_BASE && id < IDM_LANG_BASE + g_lang_count) { g_cur = id - IDM_LANG_BASE; SetWindowTextW(g_hwnd, T(0)); rebuild_lang_menu(); populate_tree(); // Rebuild ALL menus with new language HMENU hBar = GetMenu(g_hwnd); HMENU hFile = CreatePopupMenu(); AppendMenuW(hFile, MF_STRING, IDM_NEW, T(6)); AppendMenuW(hFile, MF_STRING, IDM_OPEN, T(7)); AppendMenuW(hFile, MF_STRING, IDM_SAVE, T(8)); AppendMenuW(hFile, MF_SEPARATOR, 0, NULL); AppendMenuW(hFile, MF_STRING, IDM_ABOUT, T(16)); RemoveMenu(hBar, 0, MF_BYPOSITION); InsertMenuW(hBar, 0, MF_BYPOSITION | MF_POPUP, (UINT_PTR)hFile, T(1)); DestroyMenu(GetSubMenu(hBar, 1)); // old build menu gone after insert // Rebuild build menu HMENU hBuild = CreatePopupMenu(); AppendMenuW(hBuild, MF_STRING, IDM_RUN, T(10)); AppendMenuW(hBuild, MF_SEPARATOR, 0, NULL); AppendMenuW(hBuild, MF_STRING, IDM_BUILD, T(11)); AppendMenuW(hBuild, MF_STRING, IDM_PACKAGE, T(12)); RemoveMenu(hBar, 1, MF_BYPOSITION); InsertMenuW(hBar, 1, MF_BYPOSITION | MF_POPUP, (UINT_PTR)hBuild, T(2)); DestroyMenu(GetSubMenu(hBar, 3)); // old help // Rebuild help menu HMENU hHelp = CreatePopupMenu(); AppendMenuW(hHelp, MF_STRING, IDM_ABOUT, T(16)); RemoveMenu(hBar, 3, MF_BYPOSITION); InsertMenuW(hBar, 3, MF_BYPOSITION | MF_POPUP, (UINT_PTR)hHelp, T(4)); DrawMenuBar(g_hwnd); } break; } case WM_NOTIFY: { NMHDR* nm = (NMHDR*)l; if (nm->idFrom == IDC_TREE && nm->code == TVN_SELCHANGED) { TVITEMW ti = {0}; ti.mask = TVIF_TEXT | TVIF_HANDLE; ti.hItem = TreeView_GetSelection(g_tree); WCHAR name[MAX_PATH]; ti.pszText = name; ti.cchTextMax = MAX_PATH; TreeView_GetItem(g_tree, &ti); if (!ti.hItem) break; HTREEITEM par = TreeView_GetParent(g_tree, ti.hItem); WCHAR full[MAX_PATH]; if (par) { WCHAR parent[MAX_PATH]={0}; TVITEMW pti={0}; pti.mask=TVIF_TEXT; pti.hItem=par; pti.pszText=parent; pti.cchTextMax=MAX_PATH; TreeView_GetItem(g_tree, &pti); wsprintfW(full, L"%s\\%s\\%s", g_engine_dir, parent, name); } else wsprintfW(full, L"%s\\%s", g_engine_dir, name); DWORD attr = GetFileAttributesW(full); if (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY)) open_file_at(full); } break; } case WM_SIZE: { int w2 = LOWORD(l), h2 = HIWORD(l); if (w2<100||h2<100) break; int tw=220, ch=160; MoveWindow(g_tree,0,0,tw,h2-ch,TRUE); MoveWindow(g_edit,tw+4,0,w2-tw-4,h2-ch,TRUE); MoveWindow(g_console,0,h2-ch,w2,ch-24,TRUE); break; } case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProcW(h, m, w, l); } int WINAPI wWinMain(HINSTANCE hI, HINSTANCE hP, LPWSTR nC, int nS) { (void)hP; (void)nC; (void)nS; GetModuleFileNameW(NULL, g_engine_dir, MAX_PATH); WCHAR* sl = wcsrchr(g_engine_dir, L'\\'); if (sl) *sl = 0; sl = wcsrchr(g_engine_dir, L'\\'); if (sl) *sl = 0; INITCOMMONCONTROLSEX icc = {sizeof(icc), ICC_TREEVIEW_CLASSES}; InitCommonControlsEx(&icc); g_cur = detect_lang(); WNDCLASSEXW wc = {sizeof(wc)}; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WP; wc.hInstance = hI; wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); wc.lpszClassName = L"LityEditor"; wc.hCursor = LoadCursor(NULL, IDC_ARROW); RegisterClassExW(&wc); g_hwnd = CreateWindowExW(0, L"LityEditor", T(0), WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN, 100,100,1400,900, NULL, NULL, hI, NULL); g_tree = CreateWindowExW(WS_EX_CLIENTEDGE, WC_TREEVIEWW, L"", WS_CHILD|WS_VISIBLE|TVS_HASLINES|TVS_HASBUTTONS|TVS_LINESATROOT, 0,0,220,600, g_hwnd, (HMENU)IDC_TREE, hI, NULL); g_edit = CreateWindowExW(WS_EX_CLIENTEDGE, L"EDIT", L"", WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_HSCROLL|ES_MULTILINE|ES_AUTOVSCROLL, 224,0,1176,600, g_hwnd, (HMENU)IDC_EDIT, hI, NULL); SendMessageW(g_edit, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); g_console = CreateWindowExW(WS_EX_CLIENTEDGE, L"EDIT", L"", WS_CHILD|WS_VISIBLE|WS_VSCROLL|ES_MULTILINE|ES_READONLY, 0,600,1400,136, g_hwnd, (HMENU)IDC_CONSOLE, hI, NULL); HFONT hf = CreateFontW(14,0,0,0,FW_NORMAL,0,0,0,DEFAULT_CHARSET,0,0,0,FIXED_PITCH,L"Consolas"); SendMessageW(g_console, WM_SETFONT, (WPARAM)hf, TRUE); HMENU hBar = CreateMenu(); HMENU hFile = CreatePopupMenu(); AppendMenuW(hFile,MF_STRING,IDM_NEW,T(6)); AppendMenuW(hFile,MF_STRING,IDM_OPEN,T(7)); AppendMenuW(hFile,MF_STRING,IDM_SAVE,T(8)); AppendMenuW(hFile,MF_SEPARATOR,0,NULL); AppendMenuW(hFile,MF_STRING,IDM_ABOUT,T(16)); AppendMenuW(hBar,MF_POPUP,(UINT_PTR)hFile,T(1)); HMENU hBuild = CreatePopupMenu(); AppendMenuW(hBuild,MF_STRING,IDM_RUN,T(10)); AppendMenuW(hBuild,MF_SEPARATOR,0,NULL); AppendMenuW(hBuild,MF_STRING,IDM_BUILD,T(11)); AppendMenuW(hBuild,MF_STRING,IDM_PACKAGE,T(12)); AppendMenuW(hBar,MF_POPUP,(UINT_PTR)hBuild,T(2)); HMENU hLang = CreatePopupMenu(); for (int i = 0; i < g_lang_count; i++) { WCHAR label[192]; wsprintfW(label, L"%hs (%hs)", g_langs[i].name, g_langs[i].code); UINT flags = (i == g_cur) ? (MF_STRING|MF_CHECKED) : MF_STRING; AppendMenuW(hLang, flags, IDM_LANG_BASE + i, label); } AppendMenuW(hBar,MF_POPUP,(UINT_PTR)hLang,T(5)); HMENU hHelp = CreatePopupMenu(); AppendMenuW(hHelp,MF_STRING,IDM_ABOUT,T(16)); AppendMenuW(hBar,MF_POPUP,(UINT_PTR)hHelp,T(4)); SetMenu(g_hwnd,hBar); populate_tree(); console_msg("Lity3D Editor ready.\n"); ShowWindow(g_hwnd,SW_SHOW); MSG msg; while(GetMessageW(&msg,NULL,0,0)){TranslateMessage(&msg);DispatchMessageW(&msg);} return (int)msg.wParam; }