mirror of
https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System.git
synced 2024-11-15 13:15:43 +08:00
Update Python Bindings (#348)
* Update Python bindings * Add X11Extras to setup.py for Linux builds * Update Python Bindings * Update Python bindings * Update Python Bindings
This commit is contained in:
parent
0c44accb44
commit
b5b251dffb
@ -215,6 +215,17 @@ class MainWindow(MainWindowUI, MainWindowBase):
|
||||
dock_widget = self.create_calendar_dock_widget()
|
||||
dock_widget.setTabToolTip("Tab ToolTip\nHodie est dies magna")
|
||||
dock_area = self.dock_manager.addDockWidget(QtAds.CenterDockWidgetArea, dock_widget, top_dock_area)
|
||||
# Now we create a action to test resizing of DockArea widget
|
||||
action = self.menuTests.addAction("Resize {}".format(dock_widget.windowTitle()))
|
||||
def action_triggered():
|
||||
splitter = QtAds.internal.findParent(QtAds.CDockSplitter, dock_area)
|
||||
if not splitter:
|
||||
return
|
||||
# We change the sizes of the splitter that contains the Calendar 1 widget
|
||||
# to resize the dock widget
|
||||
width = splitter.width()
|
||||
splitter.setSizes([width * 2/3, width * 1/3])
|
||||
action.triggered.connect(action_triggered)
|
||||
|
||||
# Now we add a custom button to the dock area title bar that will create
|
||||
# new editor widgets when clicked
|
@ -13,18 +13,6 @@ from PyQtAds import QtAds
|
||||
UI_FILE = os.path.join(os.path.dirname(__file__), 'mainwindow.ui')
|
||||
MainWindowUI, MainWindowBase = uic.loadUiType(UI_FILE)
|
||||
|
||||
import demo_rc # pyrcc5 demo\demo.qrc -o examples\centralWidget\demo_rc.py
|
||||
|
||||
|
||||
def svg_icon(filename: str):
|
||||
'''Helper function to create an SVG icon'''
|
||||
# This is a workaround, because because in item views SVG icons are not
|
||||
# properly scaled and look blurry or pixelate
|
||||
icon = QIcon(filename)
|
||||
icon.addPixmap(icon.pixmap(92))
|
||||
return icon
|
||||
|
||||
|
||||
class MainWindow(MainWindowUI, MainWindowBase):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
@ -46,27 +34,26 @@ class MainWindow(MainWindowUI, MainWindowBase):
|
||||
central_dock_area.setAllowedAreas(QtAds.DockWidgetArea.OuterDockAreas)
|
||||
|
||||
# create other dock widgets
|
||||
file_tree = QTreeView()
|
||||
file_tree.setFrameShape(QFrame.NoFrame)
|
||||
file_model = QFileSystemModel(file_tree)
|
||||
file_model.setRootPath(QDir.currentPath())
|
||||
file_tree.setModel(file_model)
|
||||
data_dock_widget = QtAds.CDockWidget("File system")
|
||||
data_dock_widget.setWidget(file_tree)
|
||||
data_dock_widget.resize(150, 250)
|
||||
data_dock_widget.setMinimumSize(100, 250)
|
||||
file_area = self.dock_manager.addDockWidget(QtAds.DockWidgetArea.LeftDockWidgetArea, data_dock_widget, central_dock_area)
|
||||
self.menuView.addAction(data_dock_widget.toggleViewAction())
|
||||
|
||||
table = QTableWidget()
|
||||
table.setColumnCount(3)
|
||||
table.setRowCount(10)
|
||||
table_dock_widget = QtAds.CDockWidget("Table")
|
||||
table_dock_widget = QtAds.CDockWidget("Table 1")
|
||||
table_dock_widget.setWidget(table)
|
||||
table_dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromDockWidget)
|
||||
table_dock_widget.resize(250, 150)
|
||||
table_dock_widget.setMinimumSize(200, 150)
|
||||
self.dock_manager.addDockWidget(QtAds.DockWidgetArea.BottomDockWidgetArea, table_dock_widget, file_area)
|
||||
table_area = self.dock_manager.addDockWidget(QtAds.DockWidgetArea.LeftDockWidgetArea, table_dock_widget)
|
||||
self.menuView.addAction(table_dock_widget.toggleViewAction())
|
||||
|
||||
table = QTableWidget()
|
||||
table.setColumnCount(5)
|
||||
table.setRowCount(1020)
|
||||
table_dock_widget = QtAds.CDockWidget("Table 2")
|
||||
table_dock_widget.setWidget(table)
|
||||
table_dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromDockWidget)
|
||||
table_dock_widget.resize(250, 150)
|
||||
table_dock_widget.setMinimumSize(200, 150)
|
||||
table_area = self.dock_manager.addDockWidget(QtAds.DockWidgetArea.BottomDockWidgetArea, table_dock_widget, table_area)
|
||||
self.menuView.addAction(table_dock_widget.toggleViewAction())
|
||||
|
||||
properties_table = QTableWidget()
|
||||
@ -76,7 +63,7 @@ class MainWindow(MainWindowUI, MainWindowBase):
|
||||
properties_dock_widget.setWidget(properties_table)
|
||||
properties_dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromDockWidget)
|
||||
properties_dock_widget.resize(250, 150)
|
||||
properties_dock_widget.setMinimumSize(200,150)
|
||||
properties_dock_widget.setMinimumSize(200, 150)
|
||||
self.dock_manager.addDockWidget(QtAds.DockWidgetArea.RightDockWidgetArea, properties_dock_widget, central_dock_area)
|
||||
self.menuView.addAction(properties_dock_widget.toggleViewAction())
|
||||
|
||||
@ -84,7 +71,6 @@ class MainWindow(MainWindowUI, MainWindowBase):
|
||||
|
||||
def create_perspective_ui(self):
|
||||
save_perspective_action = QAction("Create Perspective", self)
|
||||
save_perspective_action.setIcon(svg_icon(":/adsdemo/images/picture_in_picture.svg"))
|
||||
save_perspective_action.triggered.connect(self.save_perspective)
|
||||
perspective_list_action = QWidgetAction(self)
|
||||
self.perspective_combobox = QComboBox(self)
|
203
examples/dockindock/dockindock.py
Normal file
203
examples/dockindock/dockindock.py
Normal file
@ -0,0 +1,203 @@
|
||||
import sys
|
||||
|
||||
from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QMessageBox,
|
||||
QInputDialog, QMenu, QLineEdit)
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQtAds import QtAds
|
||||
|
||||
from dockindockmanager import DockInDockManager
|
||||
from perspectiveactions import LoadPerspectiveAction, RemovePerspectiveAction
|
||||
|
||||
|
||||
class DockInDockWidget(QWidget):
|
||||
def __init__(self, parent, perspectives_manager: 'PerspectivesManager', can_create_new_groups: bool = False, top_level_widget = None):
|
||||
super().__init__(parent)
|
||||
|
||||
if top_level_widget is not None:
|
||||
self.__can_create_new_groups = top_level_widget.can_create_new_groups
|
||||
else:
|
||||
self.__can_create_new_groups = can_create_new_groups
|
||||
self.__top_level_dock_widget = top_level_widget if top_level_widget else self
|
||||
self.__perspectives_manager = perspectives_manager
|
||||
self.__new_perspective_default_name: str = ''
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
layout.setContentsMargins(0,0,0,0)
|
||||
self.__mgr = DockInDockManager(self)
|
||||
layout.addWidget(self.__mgr)
|
||||
|
||||
def getManager(self) -> 'DockInDockManager':
|
||||
return self.__mgr
|
||||
|
||||
def getTopLevelDockWidget(self) -> 'DockInDockWidget':
|
||||
return self.__top_level_dock_widget
|
||||
|
||||
def canCreateNewGroups(self) -> bool:
|
||||
return self.__can_create_new_groups
|
||||
|
||||
def getPerspectivesManager(self) -> 'PerspectivesManager':
|
||||
return self.__perspectives_manager
|
||||
|
||||
def addTabWidget(self, widget: QWidget, name: str, after: QtAds.CDockAreaWidget, icon = QIcon()) -> QtAds.CDockAreaWidget:
|
||||
for existing in self.getTopLevelDockWidget().getManager().allDockWidgets(True, True):
|
||||
if existing[1].objectName() == name:
|
||||
QMessageBox.critical(self, "Error", "Name '" + name + "' already in use")
|
||||
return
|
||||
|
||||
dock_widget = QtAds.CDockWidget(name)
|
||||
dock_widget.setWidget(widget)
|
||||
dock_widget.setIcon(icon)
|
||||
|
||||
# Add the dock widget to the top dock widget area
|
||||
return self.__mgr.addDockWidget(QtAds.CenterDockWidgetArea, dock_widget, after)
|
||||
|
||||
def isTopLevel(self) -> bool:
|
||||
return not self.objectName()
|
||||
|
||||
def getGroupNameError(self, group_name: str) -> str:
|
||||
if not group_name:
|
||||
return "Group must have a non-empty name"
|
||||
|
||||
dock_managers = self.__mgr.allManagers(True, True)
|
||||
for mgr in dock_managers:
|
||||
if mgr.getGroupName() == group_name:
|
||||
return "Group name '" + group_name + "' already used"
|
||||
|
||||
return ""
|
||||
|
||||
def createGroup(self, group_name: str, insert_pos: QtAds.CDockAreaWidget, icon = QIcon()) -> 'DockInDockWidget':
|
||||
error = self.getGroupNameError(group_name)
|
||||
if error:
|
||||
QMessageBox.critical(None, "Error", error)
|
||||
return
|
||||
|
||||
child = DockInDockWidget(self, self.__top_level_dock_widget, self.__perspectives_manager)
|
||||
child.setObjectName(group_name)
|
||||
|
||||
dock_widget = QtAds.CDockWidget(group_name)
|
||||
dock_widget.setWidget(child)
|
||||
dock_widget.setIcon(icon)
|
||||
|
||||
insert_pos = self.__mgr.addDockWidget(QtAds.CenterDockWidgetArea, dock_widget, insert_pos)
|
||||
|
||||
return child, insert_pos
|
||||
|
||||
def destroyGroup(self, widget_to_remove: 'DockInDockWidget') -> None:
|
||||
top_level_widget = widget_to_remove.getTopLevelDockWidget()
|
||||
|
||||
if top_level_widget and top_level_widget != widget_to_remove:
|
||||
for dock_widget in widget_to_remove.getManager().getWidgetsInGUIOrder(): #don't use allDockWidgets to preserve sub-groups
|
||||
MoveDockWidgetAction.move(dock_widget, top_level_widget.getManager())
|
||||
assert not widget_to_remove.getManager().allDockWidgets(True, True)
|
||||
|
||||
# find widget's parent:
|
||||
for dock_widget in top_level_widget.getManager().allDockWidgets(True, True):
|
||||
if dockwidget[1].widget() == widget_to_remove:
|
||||
dockwidget[0].removeDockWidget(dockwidget[1])
|
||||
del dockwidget[1]
|
||||
# delete widgetToRemove; automatically deleted when dockWidget is deleted
|
||||
widget_to_remove = None
|
||||
break
|
||||
|
||||
assert widget_to_remove == None
|
||||
else:
|
||||
assert False
|
||||
|
||||
def attachViewMenu(self, menu: QMenu) -> None:
|
||||
menu.aboutToShow.connect(self.autoFillAttachedViewMenu)
|
||||
|
||||
def autoFillAttachedViewMenu(self) -> None:
|
||||
menu = self.sender()
|
||||
|
||||
if menu:
|
||||
menu.clear()
|
||||
self.setupViewMenu(menu)
|
||||
else:
|
||||
assert False
|
||||
|
||||
def setupViewMenu(self, menu):
|
||||
dock_managers = self.__mgr.allManagers(True, True)
|
||||
|
||||
has_perspectives_menu = False
|
||||
if self.getTopLevelDockWidget() == self:
|
||||
has_perspectives_menu = (self.__perspectives_manager != None)
|
||||
else:
|
||||
assert False
|
||||
|
||||
organize = menu
|
||||
if has_perspectives_menu:
|
||||
organize = menu.addMenu("Organize")
|
||||
|
||||
self.setupMenu(organize, dock_managers)
|
||||
|
||||
if has_perspectives_menu:
|
||||
perspectives = menu.addMenu("Perspectives")
|
||||
self.fillPerspectivesMenu(perspectives)
|
||||
|
||||
def setupMenu(self, menu: QMenu, move_to: 'list[DockInDockManager]') -> None:
|
||||
self.__mgr.fillViewMenu(menu, move_to)
|
||||
menu.addSeparator()
|
||||
move_menu = menu.addMenu("Move")
|
||||
self.__mgr.fillMoveMenu(move_menu, move_to)
|
||||
|
||||
def fillPerspectivesMenu(self, menu: QMenu):
|
||||
menu.addAction("Create perspective...", self.createPerspective)
|
||||
perspectives_names = []
|
||||
if self.__perspectives_manager:
|
||||
perspectives_names = self.__perspectives_manager.perspectiveNames()
|
||||
|
||||
if perspectives_names:
|
||||
load = menu.addMenu("Load perspective")
|
||||
for name in perspectives_names:
|
||||
load.addAction(LoadPerspectiveAction(load, name, self))
|
||||
remove = menu.addMenu("Remove perspective")
|
||||
for name in perspectives_names:
|
||||
remove.addAction(RemovePerspectiveAction(remove, name, self))
|
||||
|
||||
def setNewPerspectiveDefaultName(default_name: str) -> None:
|
||||
self.__new_perspective_default_name = default_name
|
||||
|
||||
def createPerspective(self) -> None:
|
||||
if not self.__perspectives_manager:
|
||||
return
|
||||
|
||||
name = self.__new_perspective_default_name
|
||||
if self.__new_perspective_default_name:
|
||||
index = 2
|
||||
while name in self.__perspectives_manager.perspectiveNames():
|
||||
name = f"{self.__new_perspective_default_name}({index})"
|
||||
index += 1
|
||||
|
||||
while True:
|
||||
name, ok = QInputDialog.getText(None, "Create perspective", "Enter perspective name", QLineEdit.Normal, name)
|
||||
if ok:
|
||||
if not name:
|
||||
QMessageBox.critical(None, "Error", "Perspective name cannot be empty")
|
||||
continue
|
||||
elif name in self.__perspectives_manager.perspectiveNames():
|
||||
if QMessageBox.critical(None, "Error", f"Perspective '{name}' already exists, overwrite it?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) == QMessageBox.No:
|
||||
continue
|
||||
|
||||
self.__perspectives_manager.addPerspective(name, self)
|
||||
break
|
||||
else:
|
||||
break
|
||||
|
||||
def dumpStatus(self, echo: callable = print, widget: QtAds.CDockWidget = None, tab: str = '', suffix: str = '') -> str:
|
||||
if widget is not None:
|
||||
as_mgr = DockInDockManager.dockInAManager(widget)
|
||||
if as_mgr:
|
||||
as_mgr.parent().dumpStatus(tab=tab)
|
||||
else:
|
||||
echo(tab + widget.objectName() + suffix)
|
||||
else:
|
||||
echo(tab + "Group: " + self.getManager().getGroupName())
|
||||
tab += " "
|
||||
visible_widgets = set()
|
||||
for widget in self.getManager().getWidgetsInGUIOrder():
|
||||
visible_widgets.add(widget)
|
||||
self.dumpStatus(widget=widget, tab=tab)
|
||||
|
||||
for closed in self.getManager().dockWidgetsMap().values():
|
||||
if not closed in visible_widgets:
|
||||
self.dumpStatus(widget=closed, tab=tab, suffix=" (closed)")
|
214
examples/dockindock/dockindockmanager.py
Normal file
214
examples/dockindock/dockindockmanager.py
Normal file
@ -0,0 +1,214 @@
|
||||
from PyQt5.QtWidgets import QAction, QMenu, QInputDialog, QLineEdit
|
||||
from PyQt5.QtCore import QSettings
|
||||
|
||||
from PyQtAds import QtAds
|
||||
|
||||
CHILD_PREFIX = "Child-"
|
||||
|
||||
class DockInDockManager(QtAds.CDockManager):
|
||||
def __init__(self, parent: 'DockInDockWidget'):
|
||||
super().__init__()
|
||||
self.__parent = parent
|
||||
|
||||
def parent(self) -> 'DockInDockWidget':
|
||||
return self.__parent
|
||||
|
||||
def fillViewMenu(self, menu: QMenu, move_to: 'dict[DockInDockManager]') -> None:
|
||||
from dockindock import DockInDockWidget # Prevent cyclic import
|
||||
|
||||
widgets_map = self.dockWidgetsMap()
|
||||
for key, value in widgets_map.items():
|
||||
widget = value.widget()
|
||||
action = value.toggleViewAction()
|
||||
|
||||
if isinstance(widget, DockInDockWidget):
|
||||
sub_menu = menu.addMenu(key)
|
||||
|
||||
sub_menu.addAction(action)
|
||||
sub_menu.addSeparator()
|
||||
|
||||
widget.setupMenu(sub_menu, move_to)
|
||||
else:
|
||||
menu.addAction(action)
|
||||
|
||||
if self.parent().canCreateNewGroups():
|
||||
# see how this works, to create it in the right place,
|
||||
# and also to have load perspective work when some groups are missing
|
||||
menu.addSeparator()
|
||||
menu.addAction(CreateChildDockAction(self.__parent, menu))
|
||||
|
||||
if self.parent().getTopLevelDockWidget().getManager() != self:
|
||||
menu.addAction(DestroyGroupAction( self.parent, menu))
|
||||
|
||||
def fillMoveMenu(self, menu: QMenu, move_to: 'list[DockInDockManager]') -> None:
|
||||
widgets_map = self.dockWidgetsMap()
|
||||
for key, value in widgets_map.items():
|
||||
sub_menu = menu.addMenu(key)
|
||||
|
||||
for mgr in move_to:
|
||||
# iterate over all possible target managers
|
||||
if mgr == self:
|
||||
pass # if dock is already in mgr, no reason to move it there
|
||||
elif mgr == DockInDockManager.dockInAManager(value):
|
||||
pass # if target is the group itself, can't move it there, would make no sense
|
||||
else:
|
||||
sub_menu.addAction(MoveDockWidgetAction(value, mgr, sub_menu))
|
||||
|
||||
def addPerspectiveRec(self, name: str) -> None:
|
||||
managers = self.allManagers(True, True)
|
||||
|
||||
for child in managers:
|
||||
child.addPerspective(name)
|
||||
|
||||
def openPerspectiveRec(self, name: str) -> None:
|
||||
managers = self.allManagers(True, True)
|
||||
|
||||
for child in managers:
|
||||
child.openPerspective(name)
|
||||
|
||||
def getGroupName(self) -> str:
|
||||
return self.parent().objectName()
|
||||
|
||||
def getPersistGroupName(self) -> str:
|
||||
group = "Top"
|
||||
if self.getGroupName():
|
||||
group = CHILD_PREFIX + self.getGroupName()
|
||||
return group
|
||||
|
||||
def getGroupNameFromPersistGroupName(self, persist_group_name) -> str:
|
||||
if persist_group_name.startswith(CHILD_PREFIX):
|
||||
persist_group_name = persist_group_name[len(CHILD_PREFIX):]
|
||||
else:
|
||||
assert False
|
||||
return persist_group_name
|
||||
|
||||
def loadPerspectivesRec(self, settings: QSettings) -> None:
|
||||
children = self.allManagers(True, True)
|
||||
|
||||
for mgr in children:
|
||||
settings.beginGroup(mgr.getPersistGroupName())
|
||||
mgr.loadPerspectives(settings)
|
||||
settings.endGroup()
|
||||
|
||||
def savePerspectivesRec(self, settings: QSettings) -> None:
|
||||
children = self.allManagers(True, True)
|
||||
|
||||
for mgr in children:
|
||||
settings.beginGroup(mgr.getPersistGroupName())
|
||||
mgr.savePerspectives(settings)
|
||||
settings.endGroup()
|
||||
|
||||
def removePerspectivesRec(self, settings: QSettings) -> None:
|
||||
children = self.allManagers(True, True)
|
||||
|
||||
for mgr in children:
|
||||
child.removePerspectives(child.perspectiveNames())
|
||||
|
||||
@staticmethod
|
||||
def dockInAManager(widget) -> 'DockInDockManager':
|
||||
from dockindock import DockInDockWidget # Prevent cyclic import
|
||||
|
||||
dock_widget = widget.widget() if widget else None
|
||||
return dock_widget.getManager() if isinstance(dock_widget, DockInDockWidget) else None
|
||||
|
||||
def childManagers(self, managers: 'list[DockInDockManager]', rec: bool) -> None:
|
||||
widgets = self.getWidgetsInGUIOrder()
|
||||
for widget in widgets:
|
||||
as_mgr = DockInDockManager.dockInAManager(widget)
|
||||
if as_mgr:
|
||||
managers.append(as_mgr)
|
||||
if rec:
|
||||
as_mgr.childManagers(managers, rec)
|
||||
|
||||
def allManagers(self, include_self: bool, rec: bool) -> 'list[DockInDockManager]':
|
||||
managers = []
|
||||
if include_self:
|
||||
managers.append(self)
|
||||
self.childManagers(managers, rec)
|
||||
return managers
|
||||
|
||||
def allDockWidgets(self, include_self: bool, rec: bool) -> 'list[tuple[DockInDockManager, QtAds.CDockWidget]]':
|
||||
widgets = []
|
||||
for mgr in self.allManagers(include_self, rec):
|
||||
for widget in mgr.getWidgetsInGUIOrder():
|
||||
widgets.append((mgr, widget))
|
||||
return widgets
|
||||
|
||||
def getGroupContents(self) -> 'dict[str, list[str]]':
|
||||
result = {}
|
||||
managers = self.allManagers(True, True)
|
||||
for mgr in managers:
|
||||
result[mgr.getPersistGroupName()] = mgr.dockWidgetsMap().keys()
|
||||
return result
|
||||
|
||||
def getInsertDefaultPos(self) -> QtAds.CDockAreaWidget:
|
||||
default_pos = None
|
||||
if self.dockAreaCount() != 0:
|
||||
default_pos = self.dockArea(self.dockAreaCount()-1)
|
||||
return default_pos
|
||||
|
||||
def getWidgetsInGUIOrder(self) -> 'list[QtAds.CDockWidget]':
|
||||
result = []
|
||||
for i in range(self.dockAreaCount()):
|
||||
for widget in self.dockArea(i).dockWidgets():
|
||||
result.append(widget)
|
||||
return result
|
||||
|
||||
|
||||
class CreateChildDockAction(QAction):
|
||||
def __init__(self, dock_in_dock: 'DockInDockWidget', menu: QMenu):
|
||||
super().__init__("New group...", menu)
|
||||
self.__dock_in_dock = dock_in_dock
|
||||
self.triggered.connect(self.createGroup)
|
||||
|
||||
def createGroup(self) -> None:
|
||||
name = ""
|
||||
while True:
|
||||
name, ok = QInputDialog.getText(None, self.text(), "Enter group name", QLineEdit.Normal, name)
|
||||
if ok:
|
||||
error = ""
|
||||
if self.__dock_in_dock.getTopLevelDockWidget():
|
||||
error = self.__dock_in_dock.getTopLevelDockWidget().getGroupNameError(name)
|
||||
else:
|
||||
assert False
|
||||
|
||||
if not error:
|
||||
self.__dock_in_dock.createGroup(name, None)
|
||||
break
|
||||
else:
|
||||
QMessageBox.critical(None, "Error", error)
|
||||
continue
|
||||
else:
|
||||
break
|
||||
|
||||
class DestroyGroupAction(QAction):
|
||||
def __init__(self, widget: 'DockInDockWidget', menu: QMenu):
|
||||
super().__init__("Destroy" + widget.getManager().getGroupName(), menu)
|
||||
self.__widget = widget
|
||||
self.triggered.connect(self.destroyGroup)
|
||||
|
||||
def destroyGroup(self) -> None:
|
||||
self.__widget.getTopLevelDockWidget().destroyGroup(self.__widget)
|
||||
|
||||
|
||||
class MoveDockWidgetAction(QAction):
|
||||
def __init__(self, widget: 'DockInDockWidget', move_to: DockInDockManager, menu: QMenu):
|
||||
super().__init__(menu)
|
||||
self.__widget = widget
|
||||
self.__move_to = move_to
|
||||
|
||||
if move_to.parent().isTopLevel():
|
||||
self.setText("To top")
|
||||
else:
|
||||
self.setText(f"To {move_to.parent().objectName()}")
|
||||
self.triggered.connect(self._move)
|
||||
|
||||
def _move(self) -> None:
|
||||
self.move(self.__widget, self.__move_to)
|
||||
|
||||
def move(self, widget: QtAds.CDockWidget, move_to: QtAds.CDockManager) -> None:
|
||||
if widget and move_to:
|
||||
widget.dockManager().removeDockWidget(widget)
|
||||
move_to.addDockWidget(QtAds.CenterDockWidgetArea, widget, move_to.getInsertDefaultPos())
|
||||
else:
|
||||
assert False
|
72
examples/dockindock/main.py
Normal file
72
examples/dockindock/main.py
Normal file
@ -0,0 +1,72 @@
|
||||
import sys
|
||||
import os
|
||||
import atexit
|
||||
|
||||
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQtAds import QtAds
|
||||
|
||||
from perspectives import PerspectivesManager
|
||||
from dockindock import DockInDockWidget
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.perspectives_manager = PerspectivesManager("persist")
|
||||
self.resize(400, 400)
|
||||
self.dock_manager = DockInDockWidget(self, self.perspectives_manager, can_create_new_groups=True)
|
||||
self.setCentralWidget(self.dock_manager)
|
||||
self.dock_manager.attachViewMenu(self.menuBar().addMenu("View"))
|
||||
|
||||
previous_dock_widget = None
|
||||
for i in range(3):
|
||||
l = QLabel()
|
||||
l.setWordWrap(True)
|
||||
l.setAlignment(Qt.AlignTop | Qt.AlignLeft)
|
||||
l.setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ")
|
||||
|
||||
previous_dock_widget = self.dock_manager.addTabWidget(l, f"Top label {i}", previous_dock_widget)
|
||||
|
||||
last_top_level_dock = previous_dock_widget
|
||||
|
||||
for j in range(2):
|
||||
group_manager, _ = self.dock_manager.createGroup(f"Group {j}", last_top_level_dock)
|
||||
|
||||
previous_dock_widget = None
|
||||
|
||||
for i in range(3):
|
||||
# Create example content label - this can be any application specific widget
|
||||
l = QLabel()
|
||||
l.setWordWrap(True)
|
||||
l.setAlignment(Qt.AlignTop | Qt.AlignLeft)
|
||||
l.setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ")
|
||||
|
||||
previous_dock_widget = group_manager.addTabWidget(l, f"ZInner {j}/{i}", previous_dock_widget)
|
||||
|
||||
# create sub-group
|
||||
sub_group, _ = group_manager.createGroup(f"SubGroup {j}", previous_dock_widget)
|
||||
previous_dock_widget = None
|
||||
for i in range(3):
|
||||
# Create example content label - this can be any application specific widget
|
||||
l = QLabel()
|
||||
l.setWordWrap(True)
|
||||
l.setAlignment(Qt.AlignTop | Qt.AlignLeft)
|
||||
l.setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ")
|
||||
|
||||
previous_dock_widget = sub_group.addTabWidget(l, f"SubInner {j}/{i}", previous_dock_widget)
|
||||
|
||||
self.perspectives_manager.loadPerspectives()
|
||||
|
||||
atexit.register(self.cleanup)
|
||||
|
||||
def cleanup(self):
|
||||
self.perspectives_manager.savePerspectives()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
w = MainWindow()
|
||||
w.show()
|
||||
app.exec_()
|
25
examples/dockindock/perspectiveactions.py
Normal file
25
examples/dockindock/perspectiveactions.py
Normal file
@ -0,0 +1,25 @@
|
||||
from PyQt5.QtWidgets import QAction, QMenu
|
||||
|
||||
|
||||
class LoadPerspectiveAction(QAction):
|
||||
def __init__(self, parent: QMenu, name: str, dock_manager: 'DockInDockWidget'):
|
||||
super().__init__(name, parent)
|
||||
self.name = name
|
||||
self.dock_manager = dock_manager
|
||||
|
||||
self.triggered.connect(self.load)
|
||||
|
||||
def load(self):
|
||||
self.dock_manager.getPerspectivesManager().openPerspective(self.name, self.dock_manager)
|
||||
|
||||
|
||||
class RemovePerspectiveAction(QAction):
|
||||
def __init__(self, parent: QMenu, name: str, dock_manager: 'DockInDockWidget'):
|
||||
super().__init__(name, parent)
|
||||
self.name = name
|
||||
self.dock_manager = dock_manager
|
||||
|
||||
self.triggered.connect(self.remove)
|
||||
|
||||
def remove(self):
|
||||
self.dock_manager.getPerspectivesManager().removePerspective(self.name)
|
203
examples/dockindock/perspectives.py
Normal file
203
examples/dockindock/perspectives.py
Normal file
@ -0,0 +1,203 @@
|
||||
import os
|
||||
import tempfile
|
||||
import shutil
|
||||
import atexit
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, QSettings, QObject
|
||||
from PyQtAds import QtAds
|
||||
|
||||
from dockindockmanager import DockInDockManager
|
||||
from dockindock import DockInDockWidget
|
||||
|
||||
GROUP_PREFIX = "Group"
|
||||
|
||||
def findWidget(name, managers: 'list[DockInDockManager]') -> QtAds.CDockWidget:
|
||||
for mgr in managers:
|
||||
widget = mgr.findDockWidget(name)
|
||||
if widget:
|
||||
return widget
|
||||
|
||||
|
||||
class PerspectiveInfo:
|
||||
# Partially bypass ADS perspective management, store list here
|
||||
# and then ADS will only have one perspective loaded
|
||||
# this is because all docking widgets must exist when a perspective is loaded
|
||||
# we will guarantee that!
|
||||
|
||||
settings = QSettings()
|
||||
groups: 'dict[str, list[str]]' = {}
|
||||
|
||||
|
||||
class PerspectivesManager(QObject):
|
||||
perspectivesListChanged = pyqtSignal()
|
||||
openingPerspective = pyqtSignal()
|
||||
openedPerspective = pyqtSignal()
|
||||
|
||||
def __init__(self, perspectives_folder):
|
||||
super().__init__()
|
||||
self.__perspectives_folder = perspectives_folder
|
||||
self.__perspectives = {}
|
||||
atexit.register(self.cleanup)
|
||||
|
||||
def cleanup(self):
|
||||
for perspective in self.__perspectives.values():
|
||||
filename = perspective.settings.fileName()
|
||||
try:
|
||||
os.remove(filename)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
def perspectiveNames(self) -> 'list[str]':
|
||||
return self.__perspectives.keys()
|
||||
|
||||
def addPerspective(self, name: str, widget: DockInDockWidget) -> None:
|
||||
if self.__perspectives_folder:
|
||||
self.__perspectives[name] = perspective = PerspectiveInfo()
|
||||
perspective.settings = self.getSettingsObject(self.getSettingsFileName(name, True))
|
||||
perspective.groups = widget.getManager().getGroupContents()
|
||||
|
||||
# save perspective internally
|
||||
widget.getManager().addPerspectiveRec(name)
|
||||
# store it in QSettings object
|
||||
widget.getManager().savePerspectivesRec(perspective.settings)
|
||||
# remove internal perspectives
|
||||
widget.getManager().removePerspectives(widget.getManager().perspectiveNames())
|
||||
|
||||
self.perspectivesListChanged.emit()
|
||||
|
||||
def openPerspective(name: str, widget: DockInDockWidget) -> None:
|
||||
assert widget.getTopLevelDockWidget() == widget
|
||||
|
||||
if self.__perspectives_folder:
|
||||
if name in self.__perspectives:
|
||||
self.openingPerspective.emit()
|
||||
|
||||
if widget.canCreateNewGroups():
|
||||
cur_groups = widget.getManager().allManagers(True, True)
|
||||
for group in self.__perspectives[name].groups.keys():
|
||||
found = False
|
||||
for curgroup in cur_groups:
|
||||
if curgroup.getPerspectiveGroupName() == group:
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
group = DockInDockManager.getGroupNameFromPersistGroupName(group)
|
||||
|
||||
# restore group in file but not in GUI yet
|
||||
widget.createGroup(group, None)
|
||||
|
||||
cur_groups = widget.getManager().allManagers(False, True)
|
||||
for curgroup in cur_groups:
|
||||
if curgroup.getPersistGroupName() not in self.__perspectives[name].groups.keys():
|
||||
widget.destroyGroup(curgroup.parent())
|
||||
|
||||
managers = widget.getManager().allManagers(True, True)
|
||||
for group in self.__perspectives[name].groups().keys():
|
||||
for mgr in managers:
|
||||
if mgr.getPersistGroupName() == group:
|
||||
for widget_name in self.__perspectives[name].groups[group]:
|
||||
widget = findWidget(widget_name, [mgr])
|
||||
if widget:
|
||||
pass # OK, widget is already in the good manager!
|
||||
else:
|
||||
widget = findWidget(widget_name, managers)
|
||||
if widget:
|
||||
# move dock widget in the same group as it used to be when perspective was saved
|
||||
# this guarantee load/open perspectives will work smartly
|
||||
MoveDockWidgetAction.move(widget, mgr)
|
||||
|
||||
# internally load perspectives from QSettings
|
||||
widget.getManager().loadPerspectivesRec(self.__perspectives[name].settings)
|
||||
# load perspective (update GUI)
|
||||
widget.getManager().openPerspectiveRec(name)
|
||||
# remove internal perspectives
|
||||
widget.getManager().removePerspectives(widget.getManager().perspectiveNames())
|
||||
|
||||
self.openedPerspective().emit()
|
||||
else:
|
||||
assert False
|
||||
|
||||
def removePerspectives(self) -> None:
|
||||
self.__perspectives.clear()
|
||||
self.perspectivesListChanged.emit()
|
||||
|
||||
def removePerspective(self, name: str) -> None:
|
||||
del self.__perspectives[name]
|
||||
self.perspectivesListChanged.emit()
|
||||
|
||||
def getSettingsFileName(self, perspective: str, temp: bool) -> str:
|
||||
name = "perspectives.ini" if not perspective else f"perspectives_{perspective + '.tmp' if temp else perspective + '.ini'}"
|
||||
|
||||
return os.path.join(self.__perspectives_folder, name)
|
||||
|
||||
def getSettingsObject(self, file_path: str) -> QSettings:
|
||||
return QSettings(file_path, QSettings.IniFormat)
|
||||
|
||||
def loadPerspectives(self) -> None:
|
||||
if self.__perspectives_folder:
|
||||
tempfile.mktemp(dir=self.__perspectives_folder)
|
||||
|
||||
self.__perspectives.clear()
|
||||
|
||||
main_settings = self.getSettingsObject(self.getSettingsFileName("", False))
|
||||
debug = main_settings.fileName()
|
||||
|
||||
size = main_settings.beginReadArray("Perspectives")
|
||||
|
||||
for i in range(0, size):
|
||||
main_settings.setArrayIndex(i)
|
||||
perspective = main_settings.value("Name")
|
||||
|
||||
if perspective:
|
||||
to_load = self.getSettingsFileName(perspective, False)
|
||||
loaded = self.getSettingsFileName(perspective, True)
|
||||
|
||||
try:
|
||||
os.remove(loaded)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
if not shutil.copy(to_load, loaded):
|
||||
assert False
|
||||
|
||||
self.__perspectives[perspective] = PerspectiveInfo()
|
||||
self.__perspectives[perspective].settings = self.getSettingsObject(loaded)
|
||||
|
||||
# load group info:
|
||||
main_settings.beginGroup(GROUP_PREFIX)
|
||||
for key in main_settings.allKeys():
|
||||
self.__perspectives[perspective].groups[key] = main_settings.value(key)
|
||||
main_settings.endGroup()
|
||||
else:
|
||||
assert False
|
||||
|
||||
main_settings.endArray()
|
||||
|
||||
self.perspectivesListChanged.emit()
|
||||
|
||||
def savePerspectives(self) -> None:
|
||||
if self.__perspectives_folder:
|
||||
main_settings = self.getSettingsObject(self.getSettingsFileName("", False))
|
||||
|
||||
# Save list of perspective and group organization
|
||||
main_settings.beginWriteArray("Perspectives", len(self.__perspectives))
|
||||
for i, perspective in enumerate(self.__perspectives.keys()):
|
||||
main_settings.setArrayIndex(i)
|
||||
main_settings.setValue("Name", perspective)
|
||||
main_settings.beginGroup(GROUP_PREFIX)
|
||||
for group in self.__perspectives[perspective].groups.keys():
|
||||
main_settings.setValue(group, list(self.__perspectives[perspective].groups[group]))
|
||||
main_settings.endGroup()
|
||||
main_settings.endArray()
|
||||
|
||||
# Save perspectives themselves
|
||||
for perspective_name in self.__perspectives.keys():
|
||||
to_save = self.getSettingsFileName(perspective_name, False)
|
||||
settings = self.__perspectives[perspective_name].settings
|
||||
settings.sync()
|
||||
|
||||
try:
|
||||
os.remove(to_save)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
if not shutil.copy(settings.fileName(), to_save):
|
||||
assert False
|
108
examples/emptydockarea/main.py
Normal file
108
examples/emptydockarea/main.py
Normal file
@ -0,0 +1,108 @@
|
||||
import sys
|
||||
import os
|
||||
|
||||
from PyQt5 import uic
|
||||
from PyQt5.QtCore import Qt, QSignalBlocker
|
||||
from PyQt5.QtWidgets import (QApplication, QMainWindow, QLabel, QComboBox, QTableWidget,
|
||||
QAction, QWidgetAction, QSizePolicy, QInputDialog)
|
||||
from PyQt5.QtGui import QCloseEvent
|
||||
from PyQtAds import QtAds
|
||||
|
||||
|
||||
UI_FILE = os.path.join(os.path.dirname(__file__), 'mainwindow.ui')
|
||||
MainWindowUI, MainWindowBase = uic.loadUiType(UI_FILE)
|
||||
|
||||
|
||||
class CMainWindow(MainWindowUI, MainWindowBase):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.setupUi(self)
|
||||
|
||||
QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.OpaqueSplitterResize, True)
|
||||
QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.XmlCompressionEnabled, False)
|
||||
QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FocusHighlighting, True)
|
||||
self.dock_manager = QtAds.CDockManager(self)
|
||||
|
||||
# Set central widget
|
||||
label = QLabel()
|
||||
label.setText("This is a DockArea which is always visible, even if it does not contain any DockWidgets.")
|
||||
label.setAlignment(Qt.AlignCenter)
|
||||
central_dock_widget = QtAds.CDockWidget("CentralWidget")
|
||||
central_dock_widget.setWidget(label)
|
||||
central_dock_widget.setFeature(QtAds.CDockWidget.NoTab, True)
|
||||
central_dock_area = self.dock_manager.setCentralWidget(central_dock_widget)
|
||||
|
||||
# create other dock widgets
|
||||
table = QTableWidget()
|
||||
table.setColumnCount(3)
|
||||
table.setRowCount(10)
|
||||
table_dock_widget = QtAds.CDockWidget("Table 1")
|
||||
table_dock_widget.setWidget(table)
|
||||
table_dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromDockWidget)
|
||||
table_dock_widget.resize(250, 150)
|
||||
table_dock_widget.setMinimumSize(200,150)
|
||||
self.dock_manager.addDockWidgetTabToArea(table_dock_widget, central_dock_area)
|
||||
table_area = self.dock_manager.addDockWidget(QtAds.DockWidgetArea.LeftDockWidgetArea, table_dock_widget)
|
||||
self.menuView.addAction(table_dock_widget.toggleViewAction())
|
||||
|
||||
table = QTableWidget()
|
||||
table.setColumnCount(5)
|
||||
table.setRowCount(1020)
|
||||
table_dock_widget = QtAds.CDockWidget("Table 2")
|
||||
table_dock_widget.setWidget(table)
|
||||
table_dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromDockWidget)
|
||||
table_dock_widget.resize(250, 150)
|
||||
table_dock_widget.setMinimumSize(200,150)
|
||||
self.dock_manager.addDockWidget(QtAds.DockWidgetArea.BottomDockWidgetArea, table_dock_widget, table_area)
|
||||
self.menuView.addAction(table_dock_widget.toggleViewAction())
|
||||
|
||||
properties_table = QTableWidget()
|
||||
properties_table.setColumnCount(3)
|
||||
properties_table.setRowCount(10)
|
||||
properties_dock_widget = QtAds.CDockWidget("Properties")
|
||||
properties_dock_widget.setWidget(properties_table)
|
||||
properties_dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromDockWidget)
|
||||
properties_dock_widget.resize(250, 150)
|
||||
properties_dock_widget.setMinimumSize(200,150)
|
||||
self.dock_manager.addDockWidget(QtAds.DockWidgetArea.RightDockWidgetArea, properties_dock_widget, central_dock_area)
|
||||
self.menuView.addAction(properties_dock_widget.toggleViewAction())
|
||||
|
||||
self.createPerspectiveUi()
|
||||
|
||||
def createPerspectiveUi(self):
|
||||
save_perspective_action = QAction("Create Perspective", self)
|
||||
save_perspective_action.triggered.connect(self.savePerspective)
|
||||
perspective_list_action = QWidgetAction(self)
|
||||
self.perspective_combo_box = QComboBox(self)
|
||||
self.perspective_combo_box.setSizeAdjustPolicy(QComboBox.AdjustToContents)
|
||||
self.perspective_combo_box.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
|
||||
self.perspective_combo_box.activated[str].connect(self.dock_manager.openPerspective)
|
||||
perspective_list_action.setDefaultWidget(self.perspective_combo_box)
|
||||
self.toolBar.addSeparator()
|
||||
self.toolBar.addAction(perspective_list_action)
|
||||
self.toolBar.addAction(save_perspective_action)
|
||||
|
||||
def savePerspective(self):
|
||||
perspective_name, ok = QInputDialog.getText(self, "Save Perspective", "Enter unique name:")
|
||||
if not perspective_name or not ok:
|
||||
return
|
||||
|
||||
self.dock_manager.addPerspective(perspective_name)
|
||||
blocker = QSignalBlocker(self.perspective_combo_box)
|
||||
self.perspective_combo_box.clear()
|
||||
self.perspective_combo_box.addItems(self.dock_manager.perspectiveNames())
|
||||
self.perspective_combo_box.setCurrentText(perspective_name)
|
||||
|
||||
def closeEvent(self, event: QCloseEvent):
|
||||
# Delete dock manager here to delete all floating widgets. This ensures
|
||||
# that all top level windows of the dock manager are properly closed
|
||||
self.dock_manager.deleteLater()
|
||||
super().closeEvent(event)
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
w = CMainWindow()
|
||||
w.show()
|
||||
app.exec_()
|
@ -21,6 +21,7 @@ public:
|
||||
void notifyWidgetOrAreaRelocation(QWidget* RelocatedWidget);
|
||||
void notifyFloatingWidgetDrop(ads::CFloatingDockContainer* FloatingWidget);
|
||||
ads::CDockWidget* focusedDockWidget() const;
|
||||
void setDockWidgetTabFocused(ads::CDockWidgetTab* Tab);
|
||||
|
||||
public slots:
|
||||
void setDockWidgetFocused(ads::CDockWidget* focusedNow);
|
||||
|
@ -33,8 +33,10 @@ public:
|
||||
CustomCloseHandling,
|
||||
DockWidgetFocusable,
|
||||
DockWidgetForceCloseWithArea,
|
||||
NoTab,
|
||||
DefaultDockWidgetFeatures,
|
||||
AllDockWidgetFeatures,
|
||||
DockWidgetAlwaysCloseAndDelete,
|
||||
NoDockWidgetFeatures
|
||||
};
|
||||
typedef QFlags<ads::CDockWidget::DockWidgetFeature> DockWidgetFeatures;
|
||||
|
@ -2,6 +2,40 @@
|
||||
|
||||
%If (Qt_5_0_0 -)
|
||||
|
||||
%ModuleHeaderCode
|
||||
PyObject *qtads_FindParent(PyObject* type, const QWidget *child);
|
||||
%End
|
||||
|
||||
%ModuleCode
|
||||
PyObject *qtads_FindParent(PyObject* type, const QWidget *w)
|
||||
{
|
||||
// Check that the types checking was successful.
|
||||
if (!type)
|
||||
return 0;
|
||||
|
||||
QWidget* parentWidget = w->parentWidget();
|
||||
|
||||
while (parentWidget)
|
||||
{
|
||||
PyObject *ParentImpl = sipConvertFromType(parentWidget, sipType_QObject, 0);
|
||||
if (!ParentImpl)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (PyType_IsSubtype((PyTypeObject *)type, Py_TYPE(ParentImpl)))
|
||||
return ParentImpl;
|
||||
|
||||
Py_DECREF(ParentImpl);
|
||||
|
||||
parentWidget = parentWidget->parentWidget();
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
%End
|
||||
|
||||
namespace ads
|
||||
{
|
||||
%TypeHeaderCode
|
||||
@ -55,6 +89,50 @@ namespace ads
|
||||
BitwiseOr
|
||||
};
|
||||
|
||||
namespace internal
|
||||
{
|
||||
void replaceSplitterWidget(QSplitter* Splitter, QWidget* From, QWidget* To);
|
||||
void hideEmptyParentSplitters(ads::CDockSplitter* FirstParentSplitter);
|
||||
|
||||
class CDockInsertParam
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <ads_globals.h>
|
||||
%End
|
||||
|
||||
public:
|
||||
Qt::Orientation orientation() const;
|
||||
bool append() const;
|
||||
int insertOffset() const;
|
||||
};
|
||||
ads::internal::CDockInsertParam dockAreaInsertParameters(ads::DockWidgetArea Area);
|
||||
|
||||
SIP_PYOBJECT findParent(SIP_PYTYPE type, const QWidget *w) const /TypeHint="QObject"/;
|
||||
%MethodCode
|
||||
sipRes = qtads_FindParent(a0, a1);
|
||||
|
||||
if (!sipRes)
|
||||
{
|
||||
sipIsErr = 1;
|
||||
}
|
||||
%End
|
||||
|
||||
QPixmap createTransparentPixmap(const QPixmap& Source, qreal Opacity);
|
||||
|
||||
QPoint globalPositionOf(QMouseEvent* ev);
|
||||
|
||||
void setButtonIcon(QAbstractButton* Button, QStyle::StandardPixmap StandarPixmap, ads::eIcon CustomIconId);
|
||||
|
||||
enum eRepolishChildOptions
|
||||
{
|
||||
RepolishIgnoreChildren,
|
||||
RepolishDirectChildren,
|
||||
RepolishChildrenRecursively
|
||||
};
|
||||
|
||||
void repolishStyle(QWidget* w, ads::internal::eRepolishChildOptions Options = ads::internal::RepolishIgnoreChildren);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
%End
|
||||
|
Loading…
Reference in New Issue
Block a user