|
from PyQt6 import QtCore, QtGui, QtWidgets
|
|
import os
|
|
from QToggle import QToggle
|
|
|
|
class FixedValueSlider(QtWidgets.QSlider):
|
|
def __init__(self, values, parent=None):
|
|
super().__init__(QtCore.Qt.Orientation.Horizontal, parent)
|
|
self.setMinimum(0)
|
|
self.setMaximum(len(values) - 1)
|
|
self.setTickPosition(QtWidgets.QSlider.TickPosition.TicksBelow)
|
|
self.setTickInterval(1)
|
|
self.values = values
|
|
self.valueChanged.connect(self.update_value_label)
|
|
|
|
def value(self):
|
|
return self.values[super().value()]
|
|
|
|
def setValue(self, value):
|
|
super().setValue(self.values.index(value))
|
|
|
|
def update_value_label(self, index):
|
|
self.valueChanged.emit(self.values[index])
|
|
|
|
class Ui_MainWindow(object):
|
|
def retranslateUi(self, MainWindow):
|
|
_translate = QtCore.QCoreApplication.translate
|
|
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
|
|
self.title_label.setText(_translate("MainWindow", " 🔵 LLAMACPP SERVER UI"))
|
|
self.minimize_button.setText(_translate("MainWindow", "-"))
|
|
self.close_button.setText(_translate("MainWindow", "X"))
|
|
self.model_path_label.setText(_translate("MainWindow", "Model Path:"))
|
|
self.model_browse_button.setText(_translate("MainWindow", "Browse"))
|
|
self.batch_size_label.setText(_translate("MainWindow", "Batch Size:"))
|
|
self.ctx_size_label.setText(_translate("MainWindow", "Context Size:"))
|
|
self.layers_offload_label.setText(_translate("MainWindow", "Layers Offload:"))
|
|
self.threads_label.setText(_translate("MainWindow", "Threads:"))
|
|
self.flash_attention_checkbox.setText(_translate("MainWindow", "Flash Attention"))
|
|
self.moe_checkbox.setText(_translate("MainWindow", "Custom MoE Experts"))
|
|
self.moe_experts_label.setText(_translate("MainWindow", "MoE Active Experts:"))
|
|
self.rope_freq_base_checkbox.setText(_translate("MainWindow", "Custom RoPE Freq Base"))
|
|
self.rope_freq_base_label.setText(_translate("MainWindow", "RoPE Freq Base:"))
|
|
self.mlock_checkbox.setText(_translate("MainWindow", "Use mlock"))
|
|
self.no_mmap_checkbox.setText(_translate("MainWindow", "Disable MMAP"))
|
|
self.no_kv_offload_checkbox.setText(_translate("MainWindow", "No KV Offload"))
|
|
self.run_server_button.setText(_translate("MainWindow", "Run Server"))
|
|
self.save_config_button.setText(_translate("MainWindow", "Save Config"))
|
|
self.load_config_button.setText(_translate("MainWindow", "Load Config"))
|
|
|
|
def update_batch_size_label(self, value):
|
|
self.batch_size_label.setText(f"Batch Size: {self.batch_size_values[value]}")
|
|
|
|
def update_ctx_size_label(self, value):
|
|
self.ctx_size_label.setText(f"Context Size: {self.ctx_size_values[value]}")
|
|
|
|
def setupUi(self, MainWindow):
|
|
MainWindow.setObjectName("MainWindow")
|
|
MainWindow.resize(800, 600)
|
|
|
|
|
|
self.centralwidget = QtWidgets.QWidget(MainWindow)
|
|
self.centralwidget.setObjectName("centralwidget")
|
|
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
|
|
self.verticalLayout.setObjectName("verticalLayout")
|
|
self.top_bar = QtWidgets.QFrame(self.centralwidget)
|
|
self.top_bar.setMaximumSize(QtCore.QSize(16777215, 40))
|
|
self.top_bar.setStyleSheet("background-color: #2c313c;")
|
|
self.top_bar.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
|
|
self.top_bar.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
|
|
self.top_bar.setObjectName("top_bar")
|
|
self.horizontalLayout = QtWidgets.QHBoxLayout(self.top_bar)
|
|
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
|
|
self.horizontalLayout.setSpacing(0)
|
|
self.horizontalLayout.setObjectName("horizontalLayout")
|
|
|
|
|
|
self.title_label = QtWidgets.QLabel(self.top_bar)
|
|
font = QtGui.QFont()
|
|
font.setPointSize(10)
|
|
font.setBold(True)
|
|
self.title_label.setFont(font)
|
|
self.title_label.setStyleSheet("color: white;")
|
|
self.title_label.setObjectName("title_label")
|
|
self.horizontalLayout.addWidget(self.title_label)
|
|
self.minimize_button = QtWidgets.QPushButton(self.top_bar)
|
|
self.minimize_button.setMaximumSize(QtCore.QSize(30, 30))
|
|
self.minimize_button.setStyleSheet("QPushButton {\n"
|
|
" background-color: #2c313c;\n"
|
|
" border: none;\n"
|
|
" color: white;\n"
|
|
"}\n"
|
|
"\n"
|
|
"QPushButton:hover {\n"
|
|
" background-color: #495057;\n"
|
|
"}\n"
|
|
"\n"
|
|
"QPushButton:pressed {\n"
|
|
" background-color: #6c757d;\n"
|
|
"}")
|
|
self.minimize_button.setObjectName("minimize_button")
|
|
self.horizontalLayout.addWidget(self.minimize_button)
|
|
self.close_button = QtWidgets.QPushButton(self.top_bar)
|
|
self.close_button.setMaximumSize(QtCore.QSize(30, 30))
|
|
self.close_button.setStyleSheet("QPushButton {\n"
|
|
" background-color: #2c313c;\n"
|
|
" border: none;\n"
|
|
" color: white;\n"
|
|
"}\n"
|
|
"\n"
|
|
"QPushButton:hover {\n"
|
|
" background-color: #dc3545;\n"
|
|
"}\n"
|
|
"\n"
|
|
"QPushButton:pressed {\n"
|
|
" background-color: #c82333;\n"
|
|
"}")
|
|
self.close_button.setObjectName("close_button")
|
|
self.horizontalLayout.addWidget(self.close_button)
|
|
self.verticalLayout.addWidget(self.top_bar)
|
|
self.content_area = QtWidgets.QFrame(self.centralwidget)
|
|
self.content_area.setStyleSheet("background-color: #212529;")
|
|
self.content_area.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
|
|
self.content_area.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
|
|
self.content_area.setObjectName("content_area")
|
|
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.content_area)
|
|
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
|
self.model_path_layout = QtWidgets.QHBoxLayout()
|
|
self.model_path_layout.setObjectName("model_path_layout")
|
|
self.model_path_label = QtWidgets.QLabel(self.content_area)
|
|
font = QtGui.QFont()
|
|
font.setPointSize(10)
|
|
self.model_path_label.setFont(font)
|
|
self.model_path_label.setStyleSheet("color: white;")
|
|
self.model_path_label.setObjectName("model_path_label")
|
|
self.model_path_layout.addWidget(self.model_path_label)
|
|
self.model_path_line_edit = QtWidgets.QLineEdit(self.content_area)
|
|
self.model_path_line_edit.setStyleSheet("background-color: #495057;\n"
|
|
"color: white;\n"
|
|
"border-radius: 8px;\n"
|
|
"padding: 5px;")
|
|
self.model_path_line_edit.setObjectName("model_path_line_edit")
|
|
self.model_path_layout.addWidget(self.model_path_line_edit)
|
|
self.model_browse_button = QtWidgets.QPushButton(self.content_area)
|
|
self.model_browse_button.setStyleSheet("QPushButton {\n"
|
|
" background-color: #495057;\n"
|
|
" color: white;\n"
|
|
" border-radius: 8px;\n"
|
|
" padding: 5px;\n"
|
|
"}\n"
|
|
"\n"
|
|
"QPushButton:hover {\n"
|
|
" background-color: #6c757d;\n"
|
|
"}\n"
|
|
"\n"
|
|
"QPushButton:pressed {\n"
|
|
" background-color: #343a40;\n"
|
|
"}")
|
|
self.model_browse_button.setObjectName("model_browse_button")
|
|
self.model_path_layout.addWidget(self.model_browse_button)
|
|
self.verticalLayout_2.addLayout(self.model_path_layout)
|
|
self.settings_layout = QtWidgets.QGridLayout()
|
|
self.settings_layout.setObjectName("settings_layout")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.batch_size_label = QtWidgets.QLabel(self.content_area)
|
|
font = QtGui.QFont()
|
|
font.setPointSize(10)
|
|
self.batch_size_label.setFont(font)
|
|
self.batch_size_label.setStyleSheet("color: white;")
|
|
self.batch_size_label.setObjectName("batch_size_label")
|
|
self.settings_layout.addWidget(self.batch_size_label, 0, 0, 1, 1)
|
|
|
|
self.batch_size_slider = QtWidgets.QSlider(self.content_area)
|
|
self.batch_size_slider.setStyleSheet("QSlider::groove:horizontal {\n"
|
|
" background-color: #495057;\n"
|
|
" height: 10px;\n"
|
|
"}\n"
|
|
"\n"
|
|
"QSlider::handle:horizontal {\n"
|
|
" background-color: white;\n"
|
|
" width: 20px;\n"
|
|
" border-radius: 5px;\n"
|
|
" margin: -5px 0;\n"
|
|
"}")
|
|
self.batch_size_slider.setOrientation(QtCore.Qt.Orientation.Horizontal)
|
|
self.batch_size_slider.setMinimum(0)
|
|
self.batch_size_slider.setMaximum(4)
|
|
self.batch_size_slider.setTickPosition(QtWidgets.QSlider.TickPosition.TicksBelow)
|
|
self.batch_size_slider.setTickInterval(1)
|
|
self.batch_size_values = [64, 128, 256, 512, 1024]
|
|
self.batch_size_slider.valueChanged.connect(self.update_batch_size_label)
|
|
self.batch_size_slider.setProperty("value", 3)
|
|
self.settings_layout.addWidget(self.batch_size_slider, 0, 1, 1, 3)
|
|
|
|
self.ctx_size_label = QtWidgets.QLabel(self.content_area)
|
|
font = QtGui.QFont()
|
|
font.setPointSize(10)
|
|
self.ctx_size_label.setFont(font)
|
|
self.ctx_size_label.setStyleSheet("color: white;")
|
|
self.ctx_size_label.setObjectName("ctx_size_label")
|
|
self.settings_layout.addWidget(self.ctx_size_label, 1, 0, 1, 3)
|
|
|
|
self.ctx_size_slider = QtWidgets.QSlider(self.content_area)
|
|
self.ctx_size_slider.setStyleSheet("QSlider::groove:horizontal {\n"
|
|
" background-color: #495057;\n"
|
|
" height: 10px;\n"
|
|
"}\n"
|
|
"\n"
|
|
"QSlider::handle:horizontal {\n"
|
|
" background-color: white;\n"
|
|
" width: 20px;\n"
|
|
" border-radius: 5px;\n"
|
|
" margin: -5px 0;\n"
|
|
"}")
|
|
self.ctx_size_slider.setOrientation(QtCore.Qt.Orientation.Horizontal)
|
|
self.ctx_size_slider.setMinimum(0)
|
|
self.ctx_size_slider.setMaximum(64)
|
|
|
|
self.ctx_size_slider.setTickPosition(QtWidgets.QSlider.TickPosition.TicksBelow)
|
|
self.ctx_size_slider.setTickInterval(1)
|
|
self.ctx_size_values = [1024 * (i) for i in range(65)]
|
|
self.ctx_size_slider.valueChanged.connect(self.update_ctx_size_label)
|
|
self.ctx_size_slider.setProperty("value", 4)
|
|
self.settings_layout.addWidget(self.ctx_size_slider, 1, 1, 1, 3)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.layers_offload_label = QtWidgets.QLabel(self.content_area)
|
|
font = QtGui.QFont()
|
|
font.setPointSize(10)
|
|
self.layers_offload_label.setFont(font)
|
|
self.layers_offload_label.setStyleSheet("color: white;")
|
|
self.layers_offload_label.setObjectName("layers_offload_label")
|
|
self.settings_layout.addWidget(self.layers_offload_label, 2, 0, 1, 1)
|
|
self.layers_offload_spin_box = QtWidgets.QSpinBox(self.content_area)
|
|
self.layers_offload_spin_box.setStyleSheet("background-color: #495057;\n"
|
|
"color: white;\n"
|
|
"border-radius: 8px;\n"
|
|
"padding: 5px;")
|
|
self.layers_offload_spin_box.setMinimum(0)
|
|
self.layers_offload_spin_box.setMaximum(200)
|
|
self.layers_offload_spin_box.setProperty("value", 0)
|
|
self.layers_offload_spin_box.setObjectName("layers_offload_spin_box")
|
|
self.settings_layout.addWidget(self.layers_offload_spin_box, 2, 1, 1, 1)
|
|
|
|
|
|
|
|
self.threads_label = QtWidgets.QLabel(self.content_area)
|
|
font = QtGui.QFont()
|
|
font.setPointSize(10)
|
|
self.threads_label.setFont(font)
|
|
self.threads_label.setStyleSheet("color: white;")
|
|
self.threads_label.setObjectName("threads_label")
|
|
self.settings_layout.addWidget(self.threads_label, 2, 2, 1, 1)
|
|
|
|
self.threads_spin_box = QtWidgets.QSpinBox(self.content_area)
|
|
self.threads_spin_box.setStyleSheet("background-color: #495057;\n"
|
|
"color: white;\n"
|
|
"border-radius: 8px;\n"
|
|
"padding: 5px;")
|
|
self.threads_spin_box.setMinimum(0)
|
|
self.threads_spin_box.setMaximum(os.cpu_count())
|
|
self.threads_spin_box.setProperty("value", int(os.cpu_count()/2))
|
|
self.threads_spin_box.setObjectName("threads_spin_box")
|
|
self.settings_layout.addWidget(self.threads_spin_box, 2, 3, 1, 1)
|
|
|
|
|
|
|
|
|
|
|
|
self.verticalLayout_2.addLayout(self.settings_layout)
|
|
self.advanced_options_layout = QtWidgets.QGridLayout()
|
|
self.advanced_options_layout.setObjectName("advanced_options_layout")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.moe_checkbox = QToggle()
|
|
self.moe_checkbox.setFixedHeight(20)
|
|
self.moe_checkbox.setDuration(250)
|
|
self.moe_checkbox.setStyleSheet("QToggle{"
|
|
"qproperty-bg_color:#495057;"
|
|
"qproperty-circle_color:#FFF;"
|
|
"qproperty-active_color:#0066ff;"
|
|
"qproperty-disabled_color:#383838;"
|
|
"qproperty-text_color:#FFF;}")
|
|
|
|
self.moe_checkbox.setObjectName("moe_checkbox")
|
|
self.advanced_options_layout.addWidget(self.moe_checkbox, 0, 0, 1, 1)
|
|
|
|
|
|
|
|
self.moe_experts_label = QtWidgets.QLabel(self.content_area)
|
|
font = QtGui.QFont()
|
|
font.setPointSize(10)
|
|
self.moe_experts_label.setFont(font)
|
|
self.moe_experts_label.setStyleSheet("color: white;")
|
|
self.moe_experts_label.setObjectName("moe_experts_label")
|
|
self.advanced_options_layout.addWidget(self.moe_experts_label, 0, 2, 1, 1)
|
|
self.moe_experts_spin_box = QtWidgets.QSpinBox(self.content_area)
|
|
self.moe_experts_spin_box.setStyleSheet("background-color: #495057;\n"
|
|
"color: white;\n"
|
|
"border-radius: 8px;\n"
|
|
"padding: 5px;")
|
|
self.moe_experts_spin_box.setMinimum(1)
|
|
self.moe_experts_spin_box.setMaximum(32)
|
|
self.moe_experts_spin_box.setProperty("value", 2)
|
|
self.moe_experts_spin_box.setObjectName("moe_experts_spin_box")
|
|
self.advanced_options_layout.addWidget(self.moe_experts_spin_box, 0, 3, 1, 1)
|
|
|
|
|
|
|
|
|
|
|
|
self.rope_freq_base_checkbox = QToggle()
|
|
self.rope_freq_base_checkbox.setFixedHeight(20)
|
|
self.rope_freq_base_checkbox.setDuration(250)
|
|
self.rope_freq_base_checkbox.setStyleSheet("QToggle{"
|
|
"qproperty-bg_color:#495057;"
|
|
"qproperty-circle_color:#FFF;"
|
|
"qproperty-active_color:#0066ff;"
|
|
"qproperty-disabled_color:#383838;"
|
|
"qproperty-text_color:#FFF;}")
|
|
self.rope_freq_base_checkbox.setObjectName("rope_freq_base_checkbox")
|
|
self.advanced_options_layout.addWidget(self.rope_freq_base_checkbox, 1, 0, 1, 1)
|
|
|
|
|
|
self.rope_freq_base_label = QtWidgets.QLabel(self.content_area)
|
|
font = QtGui.QFont()
|
|
font.setPointSize(10)
|
|
self.rope_freq_base_label.setFont(font)
|
|
self.rope_freq_base_label.setStyleSheet("color: white;")
|
|
self.rope_freq_base_label.setObjectName("rope_freq_base_label")
|
|
self.advanced_options_layout.addWidget(self.rope_freq_base_label, 1, 2, 1, 1)
|
|
self.rope_freq_base_spin_box = QtWidgets.QSpinBox(self.content_area)
|
|
self.rope_freq_base_spin_box.setStyleSheet("background-color: #495057;\n"
|
|
"color: white;\n"
|
|
"border-radius: 8px;\n"
|
|
"padding: 5px;")
|
|
self.rope_freq_base_spin_box.setMinimum(1)
|
|
self.rope_freq_base_spin_box.setMaximum(1000)
|
|
self.rope_freq_base_spin_box.setProperty("value", 1)
|
|
self.rope_freq_base_spin_box.setObjectName("rope_freq_base_spin_box")
|
|
self.advanced_options_layout.addWidget(self.rope_freq_base_spin_box, 1, 3, 1, 1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.flash_attention_checkbox = QToggle()
|
|
self.flash_attention_checkbox.setFixedHeight(20)
|
|
self.flash_attention_checkbox.setDuration(250)
|
|
self.flash_attention_checkbox.setStyleSheet("QToggle{"
|
|
"qproperty-bg_color:#495057;"
|
|
"qproperty-circle_color:#FFF;"
|
|
"qproperty-active_color:#0066ff;"
|
|
"qproperty-disabled_color:#383838;"
|
|
"qproperty-text_color:#FFF;}")
|
|
|
|
self.flash_attention_checkbox.setObjectName("flash_attention_checkbox")
|
|
self.advanced_options_layout.addWidget(self.flash_attention_checkbox, 2, 3, 1, 1)
|
|
|
|
|
|
self.mlock_checkbox = QToggle()
|
|
self.mlock_checkbox.setFixedHeight(20)
|
|
self.mlock_checkbox.setDuration(250)
|
|
self.mlock_checkbox.setStyleSheet("QToggle{"
|
|
"qproperty-bg_color:#495057;"
|
|
"qproperty-circle_color:#FFF;"
|
|
"qproperty-active_color:#0066ff;"
|
|
"qproperty-disabled_color:#383838;"
|
|
"qproperty-text_color:#FFF;}")
|
|
self.mlock_checkbox.setObjectName("mlock_checkbox")
|
|
self.advanced_options_layout.addWidget(self.mlock_checkbox, 2, 0, 1, 1)
|
|
|
|
|
|
self.no_mmap_checkbox = QToggle()
|
|
self.no_mmap_checkbox.setFixedHeight(20)
|
|
self.no_mmap_checkbox.setDuration(250)
|
|
self.no_mmap_checkbox.setStyleSheet("QToggle{"
|
|
"qproperty-bg_color:#495057;"
|
|
"qproperty-circle_color:#FFF;"
|
|
"qproperty-active_color:#0066ff;"
|
|
"qproperty-disabled_color:#383838;"
|
|
"qproperty-text_color:#FFF;}")
|
|
|
|
self.no_mmap_checkbox.setObjectName("no_mmap_checkbox")
|
|
self.advanced_options_layout.addWidget(self.no_mmap_checkbox, 2, 1, 1, 1)
|
|
|
|
|
|
self.no_kv_offload_checkbox = QToggle()
|
|
self.no_kv_offload_checkbox.setFixedHeight(20)
|
|
self.no_kv_offload_checkbox.setDuration(250)
|
|
self.no_kv_offload_checkbox.setStyleSheet("QToggle{"
|
|
"qproperty-bg_color:#495057;"
|
|
"qproperty-circle_color:#FFF;"
|
|
"qproperty-active_color:#0066ff;"
|
|
"qproperty-disabled_color:#383838;"
|
|
"qproperty-text_color:#FFF;}")
|
|
|
|
self.no_kv_offload_checkbox.setObjectName("no_kv_offload_checkbox")
|
|
self.advanced_options_layout.addWidget(self.no_kv_offload_checkbox, 2, 2, 1, 1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.verticalLayout_2.addLayout(self.advanced_options_layout)
|
|
self.run_server_button = QtWidgets.QPushButton(self.content_area)
|
|
self.run_server_button.setStyleSheet("QPushButton {\n"
|
|
" background-color: #0066ff;\n"
|
|
" color: white;\n"
|
|
" padding: 10px;\n"
|
|
" border-radius: 8px;\n"
|
|
" font-size: 16px;\n"
|
|
"}\n"
|
|
"\n"
|
|
"QPushButton:hover {\n"
|
|
" background-color: #1774ff;\n"
|
|
|
|
|
|
"}\n"
|
|
"\n"
|
|
"QPushButton:pressed {\n"
|
|
" background-color: #0049b8;\n"
|
|
"}")
|
|
self.run_server_button.setObjectName("run_server_button")
|
|
self.verticalLayout_2.addWidget(self.run_server_button)
|
|
self.config_layout = QtWidgets.QHBoxLayout()
|
|
self.config_layout.setObjectName("config_layout")
|
|
self.save_config_button = QtWidgets.QPushButton(self.content_area)
|
|
self.save_config_button.setStyleSheet("QPushButton {\n"
|
|
" background-color: #2e82ff;\n"
|
|
" color: white;\n"
|
|
" border-radius: 8px;\n"
|
|
" padding: 5px;\n"
|
|
"}\n"
|
|
"\n"
|
|
"QPushButton:hover {\n"
|
|
" background-color: #428eff;\n"
|
|
"}\n"
|
|
"\n"
|
|
"QPushButton:pressed {\n"
|
|
" background-color: #1e6ce3;\n"
|
|
"}")
|
|
self.save_config_button.setObjectName("save_config_button")
|
|
self.config_layout.addWidget(self.save_config_button)
|
|
self.load_config_button = QtWidgets.QPushButton(self.content_area)
|
|
self.load_config_button.setStyleSheet("QPushButton {\n"
|
|
" background-color: #2e82ff;\n"
|
|
" color: white;\n"
|
|
" border-radius: 8px;\n"
|
|
" padding: 5px;\n"
|
|
"}\n"
|
|
"\n"
|
|
"QPushButton:hover {\n"
|
|
" background-color: #428eff;\n"
|
|
"}\n"
|
|
"\n"
|
|
"QPushButton:pressed {\n"
|
|
" background-color: #1e6ce3;\n"
|
|
"}")
|
|
self.load_config_button.setObjectName("load_config_button")
|
|
self.config_layout.addWidget(self.load_config_button)
|
|
self.verticalLayout_2.addLayout(self.config_layout)
|
|
self.verticalLayout.addWidget(self.content_area)
|
|
MainWindow.setCentralWidget(self.centralwidget)
|
|
|
|
self.retranslateUi(MainWindow)
|
|
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
|
|
|
|