mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-14 18:27:51 -06:00
Move setting visibility presets into a model
Handling of "Custom" is still under consideration
This commit is contained in:
parent
872efd16b2
commit
080979caeb
5 changed files with 127 additions and 177 deletions
|
@ -57,6 +57,7 @@ from cura.Settings.QualityAndUserProfilesModel import QualityAndUserProfilesMode
|
||||||
from cura.Settings.SettingInheritanceManager import SettingInheritanceManager
|
from cura.Settings.SettingInheritanceManager import SettingInheritanceManager
|
||||||
from cura.Settings.UserProfilesModel import UserProfilesModel
|
from cura.Settings.UserProfilesModel import UserProfilesModel
|
||||||
from cura.Settings.SimpleModeSettingsManager import SimpleModeSettingsManager
|
from cura.Settings.SimpleModeSettingsManager import SimpleModeSettingsManager
|
||||||
|
from cura.Settings.SettingVisibilityProfilesModel import SettingVisibilityProfilesModel
|
||||||
|
|
||||||
|
|
||||||
from . import PlatformPhysics
|
from . import PlatformPhysics
|
||||||
|
@ -78,6 +79,7 @@ from cura.Settings.ContainerSettingsModel import ContainerSettingsModel
|
||||||
from cura.Settings.MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler
|
from cura.Settings.MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler
|
||||||
from cura.Settings.QualitySettingsModel import QualitySettingsModel
|
from cura.Settings.QualitySettingsModel import QualitySettingsModel
|
||||||
from cura.Settings.ContainerManager import ContainerManager
|
from cura.Settings.ContainerManager import ContainerManager
|
||||||
|
from cura.Settings.SettingVisibilityProfilesModel import SettingVisibilityProfilesModel
|
||||||
|
|
||||||
from cura.ObjectsModel import ObjectsModel
|
from cura.ObjectsModel import ObjectsModel
|
||||||
from cura.BuildPlateModel import BuildPlateModel
|
from cura.BuildPlateModel import BuildPlateModel
|
||||||
|
@ -356,19 +358,14 @@ class CuraApplication(QtApplication):
|
||||||
|
|
||||||
preferences.setDefault("local_file/last_used_type", "text/x-gcode")
|
preferences.setDefault("local_file/last_used_type", "text/x-gcode")
|
||||||
|
|
||||||
setting_visibily_preset_names = self.getVisibilitySettingPresetTypes()
|
default_visibility_profile = SettingVisibilityProfilesModel.getInstance().getItem(0)
|
||||||
preferences.setDefault("general/visible_settings_preset", setting_visibily_preset_names)
|
|
||||||
|
preferences.setDefault("general/visible_settings", ";".join(default_visibility_profile["settings"]))
|
||||||
|
preferences.setDefault("general/preset_setting_visibility_choice", default_visibility_profile["id"])
|
||||||
|
|
||||||
preset_setting_visibility_choice = Preferences.getInstance().getValue("general/preset_setting_visibility_choice")
|
preset_setting_visibility_choice = Preferences.getInstance().getValue("general/preset_setting_visibility_choice")
|
||||||
|
if not SettingVisibilityProfilesModel.getInstance().find("id", preset_setting_visibility_choice):
|
||||||
default_preset_visibility_group_name = "Basic"
|
Preferences.getInstance().setValue("general/preset_setting_visibility_choice", default_visibility_profile["id"])
|
||||||
if preset_setting_visibility_choice == "" or preset_setting_visibility_choice is None:
|
|
||||||
if preset_setting_visibility_choice not in setting_visibily_preset_names:
|
|
||||||
preset_setting_visibility_choice = default_preset_visibility_group_name
|
|
||||||
|
|
||||||
visible_settings = self.getVisibilitySettingPreset(settings_preset_name = preset_setting_visibility_choice)
|
|
||||||
preferences.setDefault("general/visible_settings", visible_settings)
|
|
||||||
preferences.setDefault("general/preset_setting_visibility_choice", preset_setting_visibility_choice)
|
|
||||||
|
|
||||||
self.applicationShuttingDown.connect(self.saveSettings)
|
self.applicationShuttingDown.connect(self.saveSettings)
|
||||||
self.engineCreatedSignal.connect(self._onEngineCreated)
|
self.engineCreatedSignal.connect(self._onEngineCreated)
|
||||||
|
@ -382,91 +379,6 @@ class CuraApplication(QtApplication):
|
||||||
|
|
||||||
CuraApplication.Created = True
|
CuraApplication.Created = True
|
||||||
|
|
||||||
@pyqtSlot(str, result = str)
|
|
||||||
def getVisibilitySettingPreset(self, settings_preset_name) -> str:
|
|
||||||
result = self._loadPresetSettingVisibilityGroup(settings_preset_name)
|
|
||||||
formatted_preset_settings = self._serializePresetSettingVisibilityData(result)
|
|
||||||
|
|
||||||
return formatted_preset_settings
|
|
||||||
|
|
||||||
## Serialise the given preset setting visibitlity group dictionary into a string which is concatenated by ";"
|
|
||||||
#
|
|
||||||
def _serializePresetSettingVisibilityData(self, settings_data: dict) -> str:
|
|
||||||
result_string = ""
|
|
||||||
|
|
||||||
for key in settings_data:
|
|
||||||
result_string += key + ";"
|
|
||||||
for value in settings_data[key]:
|
|
||||||
result_string += value + ";"
|
|
||||||
|
|
||||||
return result_string
|
|
||||||
|
|
||||||
## Load the preset setting visibility group with the given name
|
|
||||||
#
|
|
||||||
def _loadPresetSettingVisibilityGroup(self, visibility_preset_name) -> Dict[str, str]:
|
|
||||||
preset_dir = Resources.getPath(Resources.PresetSettingVisibilityGroups)
|
|
||||||
|
|
||||||
result = {}
|
|
||||||
right_preset_found = False
|
|
||||||
|
|
||||||
for item in os.listdir(preset_dir):
|
|
||||||
file_path = os.path.join(preset_dir, item)
|
|
||||||
if not os.path.isfile(file_path):
|
|
||||||
continue
|
|
||||||
|
|
||||||
parser = ConfigParser(allow_no_value = True) # accept options without any value,
|
|
||||||
|
|
||||||
try:
|
|
||||||
parser.read([file_path])
|
|
||||||
|
|
||||||
if not parser.has_option("general", "name"):
|
|
||||||
continue
|
|
||||||
|
|
||||||
if parser["general"]["name"] == visibility_preset_name:
|
|
||||||
right_preset_found = True
|
|
||||||
for section in parser.sections():
|
|
||||||
if section == 'general':
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
section_settings = []
|
|
||||||
for option in parser[section].keys():
|
|
||||||
section_settings.append(option)
|
|
||||||
|
|
||||||
result[section] = section_settings
|
|
||||||
|
|
||||||
if right_preset_found:
|
|
||||||
break
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
Logger.log("e", "Failed to load setting visibility preset %s: %s", file_path, str(e))
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
## Check visibility setting preset folder and returns available types
|
|
||||||
#
|
|
||||||
def getVisibilitySettingPresetTypes(self):
|
|
||||||
preset_dir = Resources.getPath(Resources.PresetSettingVisibilityGroups)
|
|
||||||
result = {}
|
|
||||||
|
|
||||||
for item in os.listdir(preset_dir):
|
|
||||||
file_path = os.path.join(preset_dir, item)
|
|
||||||
if not os.path.isfile(file_path):
|
|
||||||
continue
|
|
||||||
|
|
||||||
parser = ConfigParser(allow_no_value=True) # accept options without any value,
|
|
||||||
|
|
||||||
try:
|
|
||||||
parser.read([file_path])
|
|
||||||
|
|
||||||
if not parser.has_option("general", "name") and not parser.has_option("general", "weight"):
|
|
||||||
continue
|
|
||||||
|
|
||||||
result[parser["general"]["weight"]] = parser["general"]["name"]
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
Logger.log("e", "Failed to load setting preset %s: %s", file_path, str(e))
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _onEngineCreated(self):
|
def _onEngineCreated(self):
|
||||||
self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider())
|
self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider())
|
||||||
|
@ -904,6 +816,7 @@ class CuraApplication(QtApplication):
|
||||||
qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator")
|
qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator")
|
||||||
qmlRegisterType(UserChangesModel, "Cura", 1, 1, "UserChangesModel")
|
qmlRegisterType(UserChangesModel, "Cura", 1, 1, "UserChangesModel")
|
||||||
qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.createContainerManager)
|
qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.createContainerManager)
|
||||||
|
qmlRegisterSingletonType(SettingVisibilityProfilesModel, "Cura", 1, 0, "SettingVisibilityProfilesModel", SettingVisibilityProfilesModel.createSettingVisibilityProfilesModel)
|
||||||
|
|
||||||
# As of Qt5.7, it is necessary to get rid of any ".." in the path for the singleton to work.
|
# As of Qt5.7, it is necessary to get rid of any ".." in the path for the singleton to work.
|
||||||
actions_url = QUrl.fromLocalFile(os.path.abspath(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml")))
|
actions_url = QUrl.fromLocalFile(os.path.abspath(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml")))
|
||||||
|
|
90
cura/Settings/SettingVisibilityProfilesModel.py
Normal file
90
cura/Settings/SettingVisibilityProfilesModel.py
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
# Copyright (c) 2016 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import urllib
|
||||||
|
from configparser import ConfigParser
|
||||||
|
|
||||||
|
from PyQt5.QtCore import pyqtProperty, Qt, pyqtSignal, pyqtSlot, QUrl
|
||||||
|
|
||||||
|
from UM.Logger import Logger
|
||||||
|
from UM.Qt.ListModel import ListModel
|
||||||
|
|
||||||
|
from UM.Resources import Resources
|
||||||
|
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeTypeNotFoundError
|
||||||
|
|
||||||
|
class SettingVisibilityProfilesModel(ListModel):
|
||||||
|
IdRole = Qt.UserRole + 1
|
||||||
|
NameRole = Qt.UserRole + 2
|
||||||
|
SettingsRole = Qt.UserRole + 4
|
||||||
|
|
||||||
|
def __init__(self, parent = None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.addRoleName(self.IdRole, "id")
|
||||||
|
self.addRoleName(self.NameRole, "name")
|
||||||
|
self.addRoleName(self.SettingsRole, "settings")
|
||||||
|
|
||||||
|
self._container_ids = []
|
||||||
|
self._containers = []
|
||||||
|
|
||||||
|
self._populate()
|
||||||
|
|
||||||
|
def _populate(self):
|
||||||
|
items = []
|
||||||
|
for item in Resources.getAllResourcesOfType(Resources.PresetSettingVisibilityGroups):
|
||||||
|
try:
|
||||||
|
mime_type = MimeTypeDatabase.getMimeTypeForFile(item)
|
||||||
|
except MimeTypeNotFoundError:
|
||||||
|
Logger.log("e", "Could not determine mime type of file %s", item)
|
||||||
|
continue
|
||||||
|
|
||||||
|
id = urllib.parse.unquote_plus(mime_type.stripExtension(os.path.basename(item)))
|
||||||
|
|
||||||
|
if not os.path.isfile(item):
|
||||||
|
continue
|
||||||
|
|
||||||
|
parser = ConfigParser(allow_no_value=True) # accept options without any value,
|
||||||
|
|
||||||
|
try:
|
||||||
|
parser.read([item])
|
||||||
|
|
||||||
|
if not parser.has_option("general", "name") and not parser.has_option("general", "weight"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
settings = []
|
||||||
|
for section in parser.sections():
|
||||||
|
if section == 'general':
|
||||||
|
continue
|
||||||
|
|
||||||
|
settings.append(section)
|
||||||
|
for option in parser[section].keys():
|
||||||
|
settings.append(option)
|
||||||
|
|
||||||
|
items.append({
|
||||||
|
"id": id,
|
||||||
|
"name": parser["general"]["name"],
|
||||||
|
"weight": parser["general"]["weight"],
|
||||||
|
"settings": settings
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
Logger.log("e", "Failed to load setting preset %s: %s", file_path, str(e))
|
||||||
|
|
||||||
|
|
||||||
|
items.sort(key = lambda k: (k["weight"], k["id"]))
|
||||||
|
self.setItems(items)
|
||||||
|
|
||||||
|
# Factory function, used by QML
|
||||||
|
@staticmethod
|
||||||
|
def createSettingVisibilityProfilesModel(engine, js_engine):
|
||||||
|
return SettingVisibilityProfilesModel.getInstance()
|
||||||
|
|
||||||
|
## Get the singleton instance for this class.
|
||||||
|
@classmethod
|
||||||
|
def getInstance(cls) -> "SettingVisibilityProfilesModel":
|
||||||
|
# Note: Explicit use of class name to prevent issues with inheritance.
|
||||||
|
if not SettingVisibilityProfilesModel.__instance:
|
||||||
|
SettingVisibilityProfilesModel.__instance = cls()
|
||||||
|
return SettingVisibilityProfilesModel.__instance
|
||||||
|
|
||||||
|
__instance = None # type: "SettingVisibilityProfilesModel"
|
|
@ -10,13 +10,13 @@ import Cura 1.0 as Cura
|
||||||
Menu
|
Menu
|
||||||
{
|
{
|
||||||
id: menu
|
id: menu
|
||||||
title: "Visible Settings"
|
title: catalog.i18nc("@action:inmenu", "Visible Settings")
|
||||||
|
|
||||||
property bool showingSearchResults
|
property bool showingSearchResults
|
||||||
property bool showingAllSettings
|
property bool showingAllSettings
|
||||||
|
|
||||||
signal showAllSettings()
|
signal showAllSettings()
|
||||||
signal showSettingVisibilityProfile(string profileName)
|
signal showSettingVisibilityProfile()
|
||||||
|
|
||||||
MenuItem
|
MenuItem
|
||||||
{
|
{
|
||||||
|
@ -40,31 +40,21 @@ Menu
|
||||||
|
|
||||||
Instantiator
|
Instantiator
|
||||||
{
|
{
|
||||||
model: ListModel
|
model: Cura.SettingVisibilityProfilesModel
|
||||||
{
|
|
||||||
id: presetNamesList
|
|
||||||
Component.onCompleted:
|
|
||||||
{
|
|
||||||
// returned value is Dictionary (Ex: {1:"Basic"}, The number 1 is the weight and sort by weight)
|
|
||||||
var itemsDict = UM.Preferences.getValue("general/visible_settings_preset")
|
|
||||||
var sorted = [];
|
|
||||||
for(var key in itemsDict) {
|
|
||||||
sorted[sorted.length] = key;
|
|
||||||
}
|
|
||||||
sorted.sort();
|
|
||||||
for(var i = 0; i < sorted.length; i++) {
|
|
||||||
presetNamesList.append({text: itemsDict[sorted[i]], value: i});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MenuItem
|
MenuItem
|
||||||
{
|
{
|
||||||
text: model.text
|
text: model.name
|
||||||
checkable: true
|
checkable: true
|
||||||
checked: false
|
checked: false
|
||||||
exclusiveGroup: group
|
exclusiveGroup: group
|
||||||
onTriggered: showSettingVisibilityProfile(model.text)
|
onTriggered:
|
||||||
|
{
|
||||||
|
UM.Preferences.setValue("general/visible_settings", model.settings.join(";"));
|
||||||
|
UM.Preferences.setValue("general/preset_setting_visibility_choice", model.id);
|
||||||
|
|
||||||
|
showSettingVisibilityProfile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onObjectAdded: menu.insertItem(index, object)
|
onObjectAdded: menu.insertItem(index, object)
|
||||||
|
|
|
@ -26,8 +26,8 @@ UM.PreferencesPage
|
||||||
UM.Preferences.resetPreference("general/visible_settings")
|
UM.Preferences.resetPreference("general/visible_settings")
|
||||||
|
|
||||||
// After calling this function update Setting visibility preset combobox.
|
// After calling this function update Setting visibility preset combobox.
|
||||||
// Reset should set "Basic" setting preset
|
// Reset should set default setting preset ("Basic")
|
||||||
visibilityPreset.setBasicPreset()
|
visibilityPreset.setDefaultPreset()
|
||||||
|
|
||||||
}
|
}
|
||||||
resetEnabled: true;
|
resetEnabled: true;
|
||||||
|
@ -84,7 +84,7 @@ UM.PreferencesPage
|
||||||
if (visibilityPreset.currentIndex != visibilityPreset.model.count - 1)
|
if (visibilityPreset.currentIndex != visibilityPreset.model.count - 1)
|
||||||
{
|
{
|
||||||
visibilityPreset.currentIndex = visibilityPreset.model.count - 1
|
visibilityPreset.currentIndex = visibilityPreset.model.count - 1
|
||||||
UM.Preferences.setValue("general/preset_setting_visibility_choice", visibilityPreset.model.get(visibilityPreset.currentIndex).text)
|
UM.Preferences.setValue("general/preset_setting_visibility_choice", visibilityPreset.model.getItem(visibilityPreset.currentIndex).id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,83 +110,44 @@ UM.PreferencesPage
|
||||||
|
|
||||||
ComboBox
|
ComboBox
|
||||||
{
|
{
|
||||||
property int customOptionValue: 100
|
function setDefaultPreset()
|
||||||
|
|
||||||
function setBasicPreset()
|
|
||||||
{
|
{
|
||||||
var index = 0
|
visibilityPreset.currentIndex = 0
|
||||||
for(var i = 0; i < presetNamesList.count; ++i)
|
|
||||||
{
|
|
||||||
if(model.get(i).text == "Basic")
|
|
||||||
{
|
|
||||||
index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
visibilityPreset.currentIndex = index
|
|
||||||
}
|
}
|
||||||
|
|
||||||
id: visibilityPreset
|
id: visibilityPreset
|
||||||
width: 150
|
width: 150 * screenScaleFactor
|
||||||
anchors
|
anchors
|
||||||
{
|
{
|
||||||
top: parent.top
|
top: parent.top
|
||||||
right: parent.right
|
right: parent.right
|
||||||
}
|
}
|
||||||
|
|
||||||
model: ListModel
|
model: Cura.SettingVisibilityProfilesModel
|
||||||
{
|
textRole: "name"
|
||||||
id: presetNamesList
|
|
||||||
Component.onCompleted:
|
|
||||||
{
|
|
||||||
// returned value is Dictionary (Ex: {1:"Basic"}, The number 1 is the weight and sort by weight)
|
|
||||||
var itemsDict = UM.Preferences.getValue("general/visible_settings_preset")
|
|
||||||
var sorted = [];
|
|
||||||
for(var key in itemsDict) {
|
|
||||||
sorted[sorted.length] = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
sorted.sort();
|
|
||||||
for(var i = 0; i < sorted.length; i++) {
|
|
||||||
presetNamesList.append({text: itemsDict[sorted[i]], value: i});
|
|
||||||
}
|
|
||||||
|
|
||||||
// By agreement lets "Custom" option will have value 100
|
|
||||||
presetNamesList.append({text: "Custom", value: visibilityPreset.customOptionValue});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
currentIndex:
|
currentIndex:
|
||||||
{
|
{
|
||||||
// Load previously selected preset.
|
// Load previously selected preset.
|
||||||
var text = UM.Preferences.getValue("general/preset_setting_visibility_choice");
|
var index = model.find("id", UM.Preferences.getValue("general/preset_setting_visibility_choice"));
|
||||||
|
if(index == -1)
|
||||||
|
|
||||||
|
|
||||||
var index = 0;
|
|
||||||
for(var i = 0; i < presetNamesList.count; ++i)
|
|
||||||
{
|
{
|
||||||
if(model.get(i).text == text)
|
index = 0;
|
||||||
{
|
|
||||||
index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
onActivated:
|
onActivated:
|
||||||
{
|
{
|
||||||
// TODO What to do if user is selected "Custom from Combobox" ?
|
// TODO What to do if user is selected "Custom from Combobox" ?
|
||||||
if (model.get(index).text == "Custom"){
|
if (model.getItem(index).id == "custom"){
|
||||||
UM.Preferences.setValue("general/preset_setting_visibility_choice", model.get(index).text)
|
UM.Preferences.setValue("general/preset_setting_visibility_choice", model.get(index).id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var newVisibleSettings = CuraApplication.getVisibilitySettingPreset(model.get(index).text)
|
UM.Preferences.setValue("general/visible_settings", model.getItem(index).settings.join(";"))
|
||||||
UM.Preferences.setValue("general/visible_settings", newVisibleSettings)
|
UM.Preferences.setValue("general/preset_setting_visibility_choice", model.getItem(index).id)
|
||||||
UM.Preferences.setValue("general/preset_setting_visibility_choice", model.get(index).text)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,7 +229,7 @@ UM.PreferencesPage
|
||||||
if (visibilityPreset.currentIndex != visibilityPreset.model.count - 1)
|
if (visibilityPreset.currentIndex != visibilityPreset.model.count - 1)
|
||||||
{
|
{
|
||||||
visibilityPreset.currentIndex = visibilityPreset.model.count - 1
|
visibilityPreset.currentIndex = visibilityPreset.model.count - 1
|
||||||
UM.Preferences.setValue("general/preset_setting_visibility_choice", visibilityPreset.model.get(visibilityPreset.currentIndex).text)
|
UM.Preferences.setValue("general/preset_setting_visibility_choice", visibilityPreset.model.getItem(visibilityPreset.currentIndex).id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,10 +151,6 @@ Item
|
||||||
}
|
}
|
||||||
onShowSettingVisibilityProfile:
|
onShowSettingVisibilityProfile:
|
||||||
{
|
{
|
||||||
var newVisibleSettings = CuraApplication.getVisibilitySettingPreset(profileName)
|
|
||||||
UM.Preferences.setValue("general/visible_settings", newVisibleSettings)
|
|
||||||
UM.Preferences.setValue("general/preset_setting_visibility_choice", profileName)
|
|
||||||
|
|
||||||
base.showingAllSettings = false;
|
base.showingAllSettings = false;
|
||||||
base.findingSettings = false;
|
base.findingSettings = false;
|
||||||
filter.text = "";
|
filter.text = "";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue