88import re
99from typing import List , Dict , Any
1010import sys
11+ import webbrowser
1112
1213# Константы о программе
13- ABOUT_TOOL_VERSION = "0.2.9 "
14+ ABOUT_TOOL_VERSION = "0.3.0 "
1415ABOUT_TOOL_NAME = f"Soundscripts Editor v{ ABOUT_TOOL_VERSION } "
1516ABOUT_TOOL_DESCRIPTION = "This tool helps to edit soundscripts files used on Source Engine."
1617ABOUT_TOOL_AUTHOR = "Shitcoded by Ambiabstract (Sergey Shavin)."
1718ABOUT_TOOL_REQUESTED = "Requested by Aptekarr (Ruslan Pozdnyakov)."
1819ABOUT_TOOL_LINK = "Github: https://github.com/Ambiabstract/soundscripts_editor"
20+ ABOUT_TOOL_LINK_2 = "https://github.com/Ambiabstract/soundscripts_editor"
1921ABOUT_TOOL_DISCORD = "Discord: @Ambiabstract"
2022
2123# Константы технические
122124 "btn_focuscolor" : "#808080" , # цвет пунктирной фигни на кнопках
123125}
124126
127+ # Функции чтобы вытаскивать ресурсы из экзешника
128+ def resource_path (name : str ) -> str :
129+ base = getattr (sys , "_MEIPASS" , Path (__file__ ).parent )
130+ return str (Path (base ) / name )
131+
125132# Функция назначения иконок для всех окон
126- def setup_icons (root ):
127- if sys .platform .startswith ("win" ):
128- root .iconbitmap (default = os .path .abspath ("soundscripts_editor.ico" ))
129- else :
130- # для Linux/macOS лучше PNG через iconphoto
131- from tkinter import PhotoImage
132- img = PhotoImage (file = "soundscripts_editor.png" )
133- root .iconphoto (True , img )
133+ def setup_icons (root : tk .Tk ):
134+ img = tk .PhotoImage (file = resource_path ("soundscripts_editor.png" ))
135+ root .iconphoto (True , img )
136+ root ._icon_ref = img
134137
135138# Особая уличная магия для чёрной шапки окна
136139if sys .platform == "win32" :
@@ -450,7 +453,7 @@ def build_main_ui(self):
450453 self .btn_set_gi .pack (
451454 side = tk .LEFT , padx = buttons_padx
452455 )
453- self .btn_about = ttk .Button (self .toolbar , text = " About " , command = self . about_window )
456+ self .btn_about = ttk .Button (self .toolbar , text = " About " , command = lambda : AboutWindow ( self ) )
454457 self .btn_about .pack (
455458 side = tk .RIGHT , padx = buttons_padx
456459 )
@@ -1753,8 +1756,8 @@ def on_ok(self):
17531756 def on_cancel (self ):
17541757 self .destroy ()
17551758
1756-
17571759# Ебанутые попытки покрасить в тёмный цвет шапку окна редактирования имени ноды
1760+ '''
17581761def themed_askstring(app, title, prompt, initialvalue, **kwargs):
17591762 kwargs["parent"] = app
17601763 # до вызова: список уже существующих Toplevel
@@ -1775,6 +1778,7 @@ def themed_askstring(app, title, prompt, initialvalue, **kwargs):
17751778 enable_win_dark_titlebar(win, enable=(app.theme == "dark"))
17761779 return result
17771780'''
1781+ '''
17781782def themed_askstring(app, title, prompt, **kwargs):
17791783 kwargs["parent"] = app
17801784 # до вызова: список уже существующих Toplevel
@@ -1789,6 +1793,126 @@ def themed_askstring(app, title, prompt, **kwargs):
17891793 return result
17901794'''
17911795
1796+ # Класс окна с инфой о программе
1797+ class AboutWindow (tk .Toplevel ):
1798+ def __init__ (self , parent ):
1799+ super ().__init__ (parent )
1800+ self .title ("About" )
1801+
1802+ # self.minsize(300, 200)
1803+ self .resizable (False , False )
1804+
1805+ # Название программы и скрытый прикол
1806+ self .program_label = tk .Label (
1807+ self ,
1808+ text = ABOUT_TOOL_NAME ,
1809+ justify = "left" ,
1810+ anchor = "w" ,
1811+ wraplength = 380
1812+ )
1813+ self .program_label .pack (padx = 10 , pady = (10 , 0 ), fill = "x" )
1814+ self .program_label .bind ("<Button-1>" , self ._on_title_click )
1815+
1816+ # Основной текст
1817+ about_tool_full = ABOUT_TOOL_DESCRIPTION + "\n \n " + ABOUT_TOOL_AUTHOR + "\n " + ABOUT_TOOL_REQUESTED + "\n \n " + ABOUT_TOOL_DISCORD
1818+ text_label = tk .Label (
1819+ self , text = about_tool_full , justify = "left" , anchor = "w" , wraplength = 380
1820+ )
1821+ text_label .pack (padx = 10 , pady = 10 , fill = "x" )
1822+
1823+ # Кликабельная ссылка
1824+ self ._add_link (ABOUT_TOOL_LINK , ABOUT_TOOL_LINK_2 )
1825+ # self._add_link(ABOUT_TOOL_DISCORD, "https://discordapp.com/users/237650927484403714")
1826+
1827+ # Счетчик кликов по картинке
1828+ self ._click_count = 0
1829+ self .target_clicks_count = 10
1830+ self ._secret_shown = False
1831+
1832+ # Картинка
1833+ self .secret_image = tk .PhotoImage (file = resource_path ("memas.png" ))
1834+
1835+ # Кнопки
1836+ button_frame = tk .Frame (self )
1837+ button_frame .pack (pady = 10 )
1838+
1839+ ok_button = tk .Button (button_frame , text = " OK " , command = self .on_ok , default = "active" )
1840+ ok_button .pack (side = "left" , padx = 5 )
1841+
1842+ # Enter или Esc = OK
1843+ self .bind ("<Return>" , lambda event : self .on_ok ())
1844+ self .bind ("<Escape>" , lambda event : self .on_ok ())
1845+
1846+ # Сделать окно модальным
1847+ self .transient (parent ) # держать поверх parent и не показывать в таскбаре
1848+ self .lift () # поднять
1849+ self .update_idletasks ()
1850+ try :
1851+ self .wait_visibility () # на macOS/Wayland помогает дождаться появления
1852+ except Exception :
1853+ pass
1854+ self .focus_force () # или self.focus_set()
1855+ self .grab_set () # модальность
1856+
1857+ # Иногда на Windows полезно кратко сделать topmost, затем снять:
1858+ self .attributes ("-topmost" , True )
1859+ self .after (10 , lambda : self .attributes ("-topmost" , False ))
1860+
1861+ # Центрирование
1862+ self .update_idletasks ()
1863+ w = self .winfo_width ()
1864+ h = self .winfo_height ()
1865+ ws = self .winfo_screenwidth ()
1866+ hs = self .winfo_screenheight ()
1867+ x = (ws // 2 ) - (w // 2 )
1868+ y = (hs // 2 ) - (h // 2 )
1869+ self .geometry (f"{ w } x{ h } +{ x } +{ y } " )
1870+
1871+ # Особая уличная магия для чёрной шапки окна
1872+ enable_win_dark_titlebar (self , enable = (parent .theme == "dark" ))
1873+
1874+ # Ждать закрытия
1875+ self .wait_window ()
1876+
1877+ # Метод создания кликабельных ссылок
1878+ def _add_link (self , text , url ):
1879+ link = tk .Label (
1880+ self , text = text , fg = "#00FF72" , cursor = "hand2" , font = ("Arial" , 10 , "underline" ) # #00FFFF
1881+ )
1882+ link .pack (pady = 2 , anchor = "w" , padx = 10 )
1883+ link .bind ("<Button-1>" , lambda e : webbrowser .open_new (url ))
1884+
1885+ # Метод кликов по названию
1886+ def _on_title_click (self , event ):
1887+ self ._click_count += 1
1888+ if self ._click_count >= self .target_clicks_count and not self ._secret_shown :
1889+ self ._show_secret ()
1890+
1891+ # Специальное действие
1892+ def _show_secret (self ):
1893+ self ._secret_shown = True
1894+
1895+ secret_win = tk .Toplevel (self )
1896+ secret_win .title ("lmao title text" )
1897+ # secret_win.geometry("250x250")
1898+ secret_win .resizable (False , False )
1899+
1900+ img_label = tk .Label (secret_win , image = self .secret_image )
1901+ img_label .pack (expand = True , pady = 20 )
1902+
1903+ # Центрирование
1904+ secret_win .update_idletasks ()
1905+ w = secret_win .winfo_width ()
1906+ h = secret_win .winfo_height ()
1907+ ws = secret_win .winfo_screenwidth ()
1908+ hs = secret_win .winfo_screenheight ()
1909+ x = (ws // 2 ) - (w // 2 )
1910+ y = (hs // 2 ) - (h // 2 )
1911+ secret_win .geometry (f"{ w } x{ h } +{ x } +{ y } " )
1912+
1913+ def on_ok (self ):
1914+ self .destroy ()
1915+
17921916def main ():
17931917 app = App ()
17941918 setup_icons (app )
0 commit comments