Merge branch 'remove_modules' into UI_2.0
This commit is contained in:
@@ -1,350 +0,0 @@
|
||||
"""
|
||||
CustomTkinter Scrollable Dropdown Menu
|
||||
Author: Akash Bora
|
||||
License: MIT
|
||||
This is a custom dropdown menu for customtkinter.
|
||||
Homepage: https://github.com/Akascape/CTkScrollableDropdown
|
||||
|
||||
Advanced Scrollable Dropdown class for customtkinter widgets
|
||||
Author: Akash Bora
|
||||
"""
|
||||
import customtkinter
|
||||
import sys
|
||||
import time
|
||||
|
||||
class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
||||
|
||||
def __init__(self, attach, x=None, y=None, button_color=None, height: int = 200, width: int = None,
|
||||
fg_color=None, max_button_height: int = 20, justify="center", scrollbar_button_color=None,
|
||||
scrollbar=True, scrollbar_button_hover_color=None, frame_border_width=2, values=[],
|
||||
command=None, image_values=[], alpha: float = 0.97, double_click=False,
|
||||
resize=True, frame_border_color=None, text_color=None, autocomplete=False,
|
||||
max_height: int = None, button_pady: int = 0, min_show_button_num: int = 1,
|
||||
button_corner_radius: int = None, frame_corner_radius=0,
|
||||
**button_kwargs):
|
||||
|
||||
super().__init__(takefocus=1)
|
||||
self.transient(self.master)
|
||||
self.alpha = alpha
|
||||
self.attach = attach
|
||||
self.corner = frame_corner_radius
|
||||
# とりあえずframe_corner_radiusはframe_corner_radiusの名前のまま使いたい
|
||||
self.frame_corner_radius = frame_corner_radius
|
||||
self.padding = 0
|
||||
self.focus_something = False
|
||||
self.disable = True
|
||||
self.font_size = 12 if button_kwargs.get("font", None) is None else button_kwargs["font"]._size
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
self.after(100, lambda: self.overrideredirect(True))
|
||||
self.transparent_color = self._apply_appearance_mode(self._fg_color)
|
||||
self.attributes("-transparentcolor", self.transparent_color)
|
||||
elif sys.platform.startswith("darwin"):
|
||||
self.overrideredirect(True)
|
||||
self.transparent_color = 'systemTransparent'
|
||||
self.attributes("-transparent", True)
|
||||
self.focus_something = True
|
||||
else:
|
||||
self.overrideredirect(True)
|
||||
self.transparent_color = '#000001'
|
||||
self.corner = 0
|
||||
self.padding = 18
|
||||
self.withdraw()
|
||||
|
||||
self.hide = True
|
||||
self.attach.bind('<Configure>', lambda e: self._withdraw() if not self.disable else None, add="+")
|
||||
self.attach.winfo_toplevel().bind('<Configure>', lambda e: self._withdraw() if not self.disable else None, add="+")
|
||||
self.attach.winfo_toplevel().bind("<Triple-Button-1>", lambda e: self._withdraw() if not self.disable else None, add="+")
|
||||
self.attach.winfo_toplevel().bind("<Button-3>", lambda e: self._withdraw() if not self.disable else None, add="+")
|
||||
self.attach.winfo_toplevel().bind("<Button-2>", lambda e: self._withdraw() if not self.disable else None, add="+")
|
||||
|
||||
self.attributes('-alpha', 0)
|
||||
self.disable = False
|
||||
self.fg_color = customtkinter.ThemeManager.theme["CTkFrame"]["fg_color"] if fg_color is None else fg_color
|
||||
self.scroll_button_color = customtkinter.ThemeManager.theme["CTkScrollbar"]["button_color"] if scrollbar_button_color is None else scrollbar_button_color
|
||||
self.scroll_hover_color = customtkinter.ThemeManager.theme["CTkScrollbar"]["button_hover_color"] if scrollbar_button_hover_color is None else scrollbar_button_hover_color
|
||||
self.frame_border_color = customtkinter.ThemeManager.theme["CTkFrame"]["border_color"] if frame_border_color is None else frame_border_color
|
||||
self.button_color = customtkinter.ThemeManager.theme["CTkFrame"]["top_fg_color"] if button_color is None else button_color
|
||||
self.text_color = customtkinter.ThemeManager.theme["CTkLabel"]["text_color"] if text_color is None else text_color
|
||||
|
||||
if scrollbar is False:
|
||||
self.scroll_button_color = self.fg_color
|
||||
self.scroll_hover_color = self.fg_color
|
||||
|
||||
self.frame = customtkinter.CTkScrollableFrame(self, bg_color=self.transparent_color, fg_color=self.fg_color,
|
||||
scrollbar_button_hover_color=self.scroll_hover_color,
|
||||
corner_radius=self.corner, border_width=frame_border_width,
|
||||
scrollbar_button_color=self.scroll_button_color,
|
||||
border_color=self.frame_border_color)
|
||||
self.frame._scrollbar.grid_configure(padx=3)
|
||||
self.frame.pack(expand=True, fill="both")
|
||||
|
||||
self.dummy_entry = customtkinter.CTkEntry(self.frame, fg_color="transparent", border_width=0, height=1, width=1)
|
||||
self.no_match = customtkinter.CTkLabel(self.frame, text="No Match")
|
||||
self.height = height
|
||||
self.height_new = height
|
||||
self.width = width
|
||||
self.command = command
|
||||
self.fade = False
|
||||
self.resize = resize
|
||||
self.autocomplete = autocomplete
|
||||
self.var_update = customtkinter.StringVar()
|
||||
self.appear = False
|
||||
self.max_height = max_height
|
||||
self.button_pady = button_pady
|
||||
self.min_show_button_num = min_show_button_num
|
||||
self.button_corner_radius = button_corner_radius
|
||||
|
||||
if justify.lower()=="left":
|
||||
self.justify = "w"
|
||||
elif justify.lower()=="right":
|
||||
self.justify = "e"
|
||||
else:
|
||||
self.justify = "c"
|
||||
|
||||
self.button_height = max_button_height + self.font_size
|
||||
self.values = values
|
||||
self.button_num = len(self.values)
|
||||
self.image_values = None if len(image_values)!=len(self.values) else image_values
|
||||
|
||||
self.resizable(width=False, height=False)
|
||||
self._init_buttons(**button_kwargs)
|
||||
|
||||
# Add binding for different ctk widgets
|
||||
if double_click or self.attach.winfo_name().startswith("!ctkentry") or self.attach.winfo_name().startswith("!ctkcombobox"):
|
||||
self.attach.bind('<Double-Button-1>', lambda e: self._iconify(), add="+")
|
||||
else:
|
||||
self.attach.bind('<Button-1>', lambda e: self._iconify(), add="+")
|
||||
|
||||
if self.attach.winfo_name().startswith("!ctkcombobox"):
|
||||
self.attach._canvas.tag_bind("right_parts", "<Button-1>", lambda e: self._iconify())
|
||||
self.attach._canvas.tag_bind("dropdown_arrow", "<Button-1>", lambda e: self._iconify())
|
||||
if self.command is None:
|
||||
self.command = self.attach.set
|
||||
|
||||
if self.attach.winfo_name().startswith("!ctkoptionmenu"):
|
||||
self.attach._canvas.bind("<Button-1>", lambda e: self._iconify())
|
||||
self.attach._text_label.bind("<Button-1>", lambda e: self._iconify())
|
||||
if self.command is None:
|
||||
self.command = self.attach.set
|
||||
|
||||
self.update_idletasks()
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
if self.autocomplete:
|
||||
self.bind_autocomplete()
|
||||
|
||||
# self.deiconify()
|
||||
self.withdraw()
|
||||
|
||||
self.attributes("-alpha", self.alpha)
|
||||
|
||||
def _withdraw(self):
|
||||
if self.hide is False: self.withdraw()
|
||||
self.hide = True
|
||||
|
||||
def _update(self, a, b, c):
|
||||
self.live_update(self.attach._entry.get())
|
||||
|
||||
def bind_autocomplete(self, ):
|
||||
def appear(x):
|
||||
self.appear = True
|
||||
|
||||
if self.attach.winfo_name().startswith("!ctkcombobox"):
|
||||
self.attach._entry.configure(textvariable=self.var_update)
|
||||
self.attach._entry.bind("<Key>", appear)
|
||||
self.attach.set(self.values[0])
|
||||
self.var_update.trace_add('write', self._update)
|
||||
|
||||
if self.attach.winfo_name().startswith("!ctkentry"):
|
||||
self.attach.configure(textvariable=self.var_update)
|
||||
self.attach.bind("<Key>", appear)
|
||||
self.var_update.trace_add('write', self._update)
|
||||
|
||||
def fade_out(self):
|
||||
for i in range(100,0,-10):
|
||||
if not self.winfo_exists():
|
||||
break
|
||||
self.attributes("-alpha", i/100)
|
||||
self.update()
|
||||
time.sleep(1/100)
|
||||
|
||||
def fade_in(self):
|
||||
for i in range(0,100,10):
|
||||
if not self.winfo_exists():
|
||||
break
|
||||
self.attributes("-alpha", i/100)
|
||||
self.update()
|
||||
time.sleep(1/100)
|
||||
|
||||
def _init_buttons(self, **button_kwargs):
|
||||
self.i = 0
|
||||
self.widgets = {}
|
||||
for row in self.values:
|
||||
self.widgets[self.i] = customtkinter.CTkButton(self.frame,
|
||||
text=row,
|
||||
height=self.button_height,
|
||||
fg_color=self.button_color,
|
||||
text_color=self.text_color,
|
||||
image=self.image_values[i] if self.image_values is not None else None,
|
||||
anchor=self.justify,
|
||||
corner_radius= self.button_corner_radius,
|
||||
command=lambda k=row: self._attach_key_press(k), **button_kwargs)
|
||||
pady = 0 if self.button_num-1 == self.i else self.button_pady
|
||||
self.widgets[self.i].pack(fill="x", pady=(0, pady), padx=(self.padding, 0))
|
||||
self.i+=1
|
||||
|
||||
self.hide = False
|
||||
|
||||
def destroy_popup(self):
|
||||
self.destroy()
|
||||
self.disable = True
|
||||
|
||||
def place_dropdown(self):
|
||||
self.x_pos = self.attach.winfo_rootx() if self.x is None else self.x + self.attach.winfo_rootx()
|
||||
self.y_pos = self.attach.winfo_rooty() + self.attach.winfo_reqheight() + 5 if self.y is None else self.y + self.attach.winfo_rooty()
|
||||
self.width_new = self.attach.winfo_width() if self.width is None else self.width
|
||||
|
||||
if self.resize:
|
||||
button_height_include_pady = self.button_height + self.button_pady
|
||||
|
||||
if self.min_show_button_num < self.button_num:
|
||||
min_buttons_height = button_height_include_pady * self.min_show_button_num
|
||||
else:
|
||||
min_buttons_height = button_height_include_pady * self.button_num
|
||||
# delete last one's pady px
|
||||
min_buttons_height -= self.button_pady
|
||||
|
||||
# minor adjustment + 5px
|
||||
min_buttons_height += 5
|
||||
# adjust by frame_corner_radius
|
||||
min_buttons_height += (self.frame_corner_radius * 2)
|
||||
|
||||
if self.max_height:
|
||||
if min_buttons_height>self.max_height:
|
||||
min_buttons_height = self.max_height
|
||||
|
||||
self.height_new = min_buttons_height
|
||||
|
||||
self.geometry('{}x{}+{}+{}'.format(self.width_new, self.height_new,
|
||||
self.x_pos, self.y_pos))
|
||||
self.fade_in()
|
||||
self.attributes('-alpha', self.alpha)
|
||||
|
||||
def _iconify(self):
|
||||
if self.disable: return
|
||||
if self.hide:
|
||||
self._deiconify()
|
||||
self.place_dropdown()
|
||||
if self.focus_something:
|
||||
self.dummy_entry.pack()
|
||||
self.dummy_entry.focus_set()
|
||||
self.after(100, self.dummy_entry.pack_forget)
|
||||
self.hide = False
|
||||
self.focus_set()
|
||||
self.focus()
|
||||
else:
|
||||
self.withdraw()
|
||||
self.hide = True
|
||||
|
||||
def _attach_key_press(self, k):
|
||||
self.fade = True
|
||||
if self.command:
|
||||
self.command(k)
|
||||
self.fade = False
|
||||
self.fade_out()
|
||||
self.withdraw()
|
||||
self.hide = True
|
||||
|
||||
def live_update(self, string=None):
|
||||
if not self.appear: return
|
||||
if self.disable: return
|
||||
if self.fade: return
|
||||
if string:
|
||||
self._deiconify()
|
||||
i=1
|
||||
for key in self.widgets.keys():
|
||||
s = self.widgets[key].cget("text")
|
||||
if not s.startswith(string):
|
||||
self.widgets[key].pack_forget()
|
||||
else:
|
||||
self.widgets[key].pack(fill="x", pady=2, padx=(self.padding, 0))
|
||||
i+=1
|
||||
|
||||
if i==1:
|
||||
self.no_match.pack(fill="x", pady=2, padx=(self.padding, 0))
|
||||
else:
|
||||
self.no_match.pack_forget()
|
||||
self.button_num = i
|
||||
self.place_dropdown()
|
||||
|
||||
else:
|
||||
self.no_match.pack_forget()
|
||||
self.button_num = len(self.values)
|
||||
for key in self.widgets.keys():
|
||||
self.widgets[key].destroy()
|
||||
self._init_buttons()
|
||||
self.place_dropdown()
|
||||
|
||||
self.frame._parent_canvas.yview_moveto(0.0)
|
||||
self.appear = False
|
||||
|
||||
def insert(self, value, **kwargs):
|
||||
self.widgets[self.i] = customtkinter.CTkButton(self.frame,
|
||||
text=value,
|
||||
height=self.button_height,
|
||||
fg_color=self.button_color,
|
||||
text_color=self.text_color,
|
||||
anchor=self.justify,
|
||||
command=lambda k=value: self._attach_key_press(k), **kwargs)
|
||||
self.widgets[self.i].pack(fill="x", pady=2, padx=(self.padding, 0))
|
||||
self.i+=1
|
||||
self.values.append(value)
|
||||
|
||||
def _deiconify(self):
|
||||
if len(self.values)>0:
|
||||
self.deiconify()
|
||||
|
||||
def popup(self, x=None, y=None):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.hide = True
|
||||
self._iconify()
|
||||
|
||||
def configure(self, **kwargs):
|
||||
if "height" in kwargs:
|
||||
self.height = kwargs.pop("height")
|
||||
self.height_new = self.height
|
||||
|
||||
if "alpha" in kwargs:
|
||||
self.alpha = kwargs.pop("alpha")
|
||||
|
||||
if "width" in kwargs:
|
||||
self.width = kwargs.pop("width")
|
||||
|
||||
if "fg_color" in kwargs:
|
||||
self.frame.configure(fg_color=kwargs.pop("fg_color"))
|
||||
|
||||
if "values" in kwargs:
|
||||
self.values = kwargs.pop("values")
|
||||
self.image_values = None
|
||||
for key in self.widgets.keys():
|
||||
self.widgets[key].destroy()
|
||||
self._init_buttons()
|
||||
|
||||
if "image_values" in kwargs:
|
||||
self.image_values = kwargs.pop("image_values")
|
||||
self.image_values = None if len(self.image_values)!=len(self.values) else self.image_values
|
||||
if self.image_values is not None:
|
||||
i=0
|
||||
for key in self.widgets.keys():
|
||||
self.widgets[key].configure(image=self.image_values[i])
|
||||
i+=1
|
||||
|
||||
if "button_color" in kwargs:
|
||||
for key in self.widgets.keys():
|
||||
self.widgets[key].configure(fg_color=kwargs.pop("button_color"))
|
||||
|
||||
for key in self.widgets.keys():
|
||||
self.widgets[key].configure(**kwargs)
|
||||
1344
window_config.py
1344
window_config.py
File diff suppressed because it is too large
Load Diff
@@ -1,161 +0,0 @@
|
||||
import os
|
||||
from customtkinter import CTkToplevel, CTkTextbox, CTkFont
|
||||
from config import config
|
||||
|
||||
class ToplevelWindowInformation(CTkToplevel):
|
||||
def __init__(self, parent, *args, **kwargs):
|
||||
super().__init__(parent, *args, **kwargs)
|
||||
self.withdraw()
|
||||
self.parent = parent
|
||||
self.grid_columnconfigure(0, weight=1)
|
||||
self.grid_rowconfigure(0, weight=1)
|
||||
# self.geometry(f"{500}x{300}")
|
||||
self.minsize(500, 300)
|
||||
|
||||
self.after(200, lambda: self.iconbitmap(os.path.join(os.path.dirname(__file__), "img", "app.ico")))
|
||||
self.title("Information")
|
||||
# create textbox information
|
||||
self.textbox_information = CTkTextbox(
|
||||
self,
|
||||
font=CTkFont(family=config.FONT_FAMILY)
|
||||
)
|
||||
self.textbox_information.grid(row=0, column=0, padx=(10, 10), pady=(10, 10), sticky="nsew")
|
||||
textbox_information_message = """VRCT(v1.3.2)
|
||||
|
||||
# 概要
|
||||
VRChatで使用されるChatBoxをOSC経由でメッセージを送信するツールになります。
|
||||
翻訳エンジンを使用してメッセージとその翻訳部分を同時に送信することができます。
|
||||
(翻訳エンジンはDeepL,Google,Bingに対応)
|
||||
|
||||
# 使用方法
|
||||
初期設定時
|
||||
0. VRChatのOSCを有効にする(重要)
|
||||
|
||||
(任意)
|
||||
1. DeepLのAPIを使用するためにアカウント登録し、認証キーを取得する
|
||||
2. ギアアイコンのボタンでconfigウィンドウを開く
|
||||
3. ParameterタブのDeepL Auth Keyに認証キーを記載
|
||||
4. configウィンドウを閉じる
|
||||
|
||||
通常使用時
|
||||
1. メッセージボックスにメッセージを記入
|
||||
2. Enterキーを押し、メッセージを送信する
|
||||
|
||||
# その他の設定
|
||||
translation チェックボックス: 翻訳の有効無効
|
||||
voice2chatbox チェックボックス : マイクの音声を文字起こししてチャットボックスに送信する
|
||||
speaker2log チェックボックス : スピーカーの音声から文字起こししてログに表示する
|
||||
foreground チェックボックス: 最前面表示の有効無効
|
||||
|
||||
テキストボックス
|
||||
logタブ
|
||||
すべてのログを表示
|
||||
sendタブ
|
||||
送信したメッセージを表示
|
||||
receiveタブ
|
||||
受信したメッセージを表示
|
||||
systemタブ
|
||||
機能についてのメッセージを表示
|
||||
|
||||
configウィンドウ
|
||||
UIタブ
|
||||
Transparency: ウィンドウの透過度の調整
|
||||
Appearance Theme: ウィンドウテーマを選択
|
||||
UI Scaling: UIサイズを調整
|
||||
Font Family: 表示フォントを選択
|
||||
UI Language: UIの表示言語を選択
|
||||
Translationタブ
|
||||
Select Translator: 翻訳エンジンの変更
|
||||
Send Language: 送信するメッセージに対して翻訳する言語[source, target]を選択
|
||||
Receive Language: 受信したメッセージに対して翻訳する言語[source, target]を選択
|
||||
Transcriptionタブ
|
||||
Input Mic Host: マイクのホストAPIを選択
|
||||
Input Mic Device: マイクを選択
|
||||
Input Mic Voice Language: 入力する音声の言語
|
||||
Input Mic Energy Threshold: 音声取得のしきい値
|
||||
Check threshold point: Input Mic Energy Thresholdのしきい値を視覚化
|
||||
Input Mic Dynamic Energy Threshold: 音声取得のしきい値の自動調整
|
||||
Input Mic Record Timeout: 音声の区切りの無音時間
|
||||
Input Mic Phase Timeout: 文字起こしする音声時間の上限
|
||||
Input Mic Max Phrases: 保留する単語の上限
|
||||
Input Mic Word Filter: MICの文字起こし時にWord Filterで設定した文字が入っていた場合にChatboxに表示しない (ex AAA,BBB,CCC)
|
||||
Input Speaker Device: スピーカーを選択
|
||||
Input Speaker Voice Language: 受信する音声の言語
|
||||
Input Speaker Energy Threshold: 音声取得のしきい値
|
||||
Check threshold point: Input Speaker Energy Thresholdのしきい値を視覚化
|
||||
Input Speaker Dynamic Energy Threshold: 音声取得のしきい値の自動調整
|
||||
Input Speaker Record Timeout: 音声の区切りの無音時間
|
||||
Input Speaker Phase Timeout: 文字起こしする音声時間の上限
|
||||
Input Speaker Max Phrases: 保留する単語の上限
|
||||
Parameterタブ
|
||||
OSC IP address: 変更不要
|
||||
OSC port: 変更不要
|
||||
DeepL Auth key: DeepLの認証キーの設定
|
||||
Message Format: 送信するメッセージのデコレーションの設定
|
||||
[message]がメッセージボックスに記入したメッセージに置換される
|
||||
[translation]が翻訳されたメッセージに置換される
|
||||
初期フォーマット:"[message]([translation])"
|
||||
Othersタブ
|
||||
Auto clear chat box: メッセージ送信後に書き込んだメッセージを空にする
|
||||
(New!) Notification XSOverlay: XSOverlayの通知機能を有効(VR only)
|
||||
|
||||
設定の初期化
|
||||
config.jsonを削除
|
||||
|
||||
# お問い合わせ
|
||||
要望などはTwitterまで
|
||||
https://twitter.com/misya_ai
|
||||
|
||||
# アップデート履歴
|
||||
[2023-05-29: v0.1b] v0.1b リリース
|
||||
[2023-05-30: v0.2b]
|
||||
- configボタンをギアアイコンに変更
|
||||
- 詳細情報のボタンを追加
|
||||
- 翻訳機能有効無効のチェックボックスを追加
|
||||
- 最前面表示の有効無効のチェックボックスを追加
|
||||
- いくつかのバグを修正
|
||||
[2023-06-03: v0.3b]
|
||||
- 全体的にUIを刷新
|
||||
- 透過機能を追加
|
||||
- テーマのLight/Dark/Systemのモードの変更機能を追加
|
||||
- UIのスケール変更機能を追加
|
||||
- フォントの変更機能を追加
|
||||
[2023-06-06: v0.4b]
|
||||
- 翻訳エンジンを追加
|
||||
- 入力と出力の翻訳言語を選択できるように変更
|
||||
[2023-06-20: v1.0]
|
||||
- マイクからの音声の文字起こし機能を追加
|
||||
- スピーカーからの音声の文字起こし機能を追加
|
||||
[2023-06-28: v1.1]
|
||||
- いくつかのバクを修正
|
||||
- 翻訳/文字起こし言語の表記を略称からわかりやすい文字に変更
|
||||
- 文字起こしの処理の軽量化
|
||||
[2023-07-05: v1.2]
|
||||
- 文字起こし精度の向上
|
||||
[2023-07-21: v1.3]
|
||||
- UIの表示言語を日本語/英語を選択できる機能を追加
|
||||
- Energy Thresholdの視覚化機能を追加
|
||||
- 文字起こしの誤認識対策のため、Word Filterを追加
|
||||
- WASAPI以外のHostAPIでもマイクとして使用できるようにHostAPIを選択できる機能を追加
|
||||
- メッセージ送信後に書き込んだメッセージを空にするか選択できる機能を追加
|
||||
- バグ対策のため、translation/voice2chatbox/speaker2log/foregroundは起動時はOFFになるように変更
|
||||
- バグ対策のため、スピーカーについて既定デバイス以外を選択した時にERRORが出るように変更
|
||||
- 半角入力時に一部の文字が書き込めないバグを修正
|
||||
[2023-07-22: v1.3.1]
|
||||
- UIの表示言語選択に韓国語を追加
|
||||
[2023-07-30: v1.3.2]
|
||||
- 試験的にXSOverlayへの通知機能を追加
|
||||
- checkbox ONの状態でもConfigを開けるように変更
|
||||
- 文字起こし言語の表示を修正
|
||||
- いくつかのバグを修正
|
||||
|
||||
# 注意事項
|
||||
再配布とかはやめてね
|
||||
"""
|
||||
|
||||
self.textbox_information.insert("end", textbox_information_message)
|
||||
self.textbox_information.configure(state='disabled')
|
||||
self.protocol("WM_DELETE_WINDOW", self.delete_window)
|
||||
|
||||
def delete_window(self):
|
||||
self.withdraw()
|
||||
Reference in New Issue
Block a user