Merge branch 'main' into transform-float-scale
This commit is contained in:
+202
@@ -0,0 +1,202 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
|
||||
# fmt: off
|
||||
class Tests():
|
||||
new_event_created = ("New Script Event created", "New Script Event not created")
|
||||
child_1_created = ("Initial Child Event created", "Initial Child Event not created")
|
||||
child_2_created = ("Second Child Event created", "Second Child Event not created")
|
||||
file_saved = ("Script event file saved", "Script event file did not save")
|
||||
method_added = ("Method added to scriptevent file", "Method not added to scriptevent file")
|
||||
method_removed = ("Method removed from scriptevent file", "Method not removed from scriptevent file")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def ScriptEvent_AddRemoveMethod_UpdatesInSC():
|
||||
"""
|
||||
Summary:
|
||||
Method can be added/removed to an existing .scriptevents file
|
||||
|
||||
Expected Behavior:
|
||||
The Method is correctly added/removed to the asset, and Script Canvas nodes are updated accordingly.
|
||||
|
||||
Test Steps:
|
||||
1) Open Asset Editor and Script Canvas windows
|
||||
2) Initially create new Script Event file with one method
|
||||
3) Verify if file is created and saved
|
||||
4) Add a new child element
|
||||
5) Update MethodNames and save file
|
||||
6) Verify if the new node exist in SC (search in node palette)
|
||||
7) Delete one method and save
|
||||
8) Verify if the node is removed in SC
|
||||
9) Close Asset Editor
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Open 3D Engine Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
from utils import TestHelper as helper
|
||||
import pyside_utils
|
||||
|
||||
# Open 3D Engine imports
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.bus as bus
|
||||
|
||||
# Pyside imports
|
||||
from PySide2 import QtWidgets, QtTest, QtCore
|
||||
|
||||
GENERAL_WAIT = 1.0 # seconds
|
||||
|
||||
FILE_PATH = os.path.join("AutomatedTesting", "TestAssets", "test_file.scriptevents")
|
||||
METHOD_NAME = "test_method_name"
|
||||
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
asset_editor = asset_editor_widget = container = menu_bar = None
|
||||
sc = node_palette = tree = search_frame = search_box = None
|
||||
|
||||
def initialize_asset_editor_qt_objects():
|
||||
nonlocal asset_editor, asset_editor_widget, container, menu_bar
|
||||
asset_editor = editor_window.findChild(QtWidgets.QDockWidget, "Asset Editor")
|
||||
asset_editor_widget = asset_editor.findChild(QtWidgets.QWidget, "AssetEditorWindowClass")
|
||||
container = asset_editor_widget.findChild(QtWidgets.QWidget, "ContainerForRows")
|
||||
menu_bar = asset_editor_widget.findChild(QtWidgets.QMenuBar)
|
||||
|
||||
def initialize_sc_qt_objects():
|
||||
nonlocal sc, node_palette, tree, search_frame, search_box
|
||||
sc = editor_window.findChild(QtWidgets.QDockWidget, "Script Canvas")
|
||||
if sc.findChild(QtWidgets.QDockWidget, "NodePalette") is None:
|
||||
action = pyside_utils.find_child_by_pattern(sc, {"text": "Node Palette", "type": QtWidgets.QAction})
|
||||
action.trigger()
|
||||
node_palette = sc.findChild(QtWidgets.QDockWidget, "NodePalette")
|
||||
tree = node_palette.findChild(QtWidgets.QTreeView, "treeView")
|
||||
search_frame = node_palette.findChild(QtWidgets.QFrame, "searchFrame")
|
||||
search_box = search_frame.findChild(QtWidgets.QLineEdit, "searchFilter")
|
||||
|
||||
def save_file():
|
||||
editor.AssetEditorWidgetRequestsBus(bus.Broadcast, "SaveAssetAs", FILE_PATH)
|
||||
action = pyside_utils.find_child_by_pattern(menu_bar, {"type": QtWidgets.QAction, "iconText": "Save"})
|
||||
action.trigger()
|
||||
# wait till file is saved, to validate that check the text of QLabel at the bottom of the AssetEditor,
|
||||
# if there are no unsaved changes we will not have any * in the text
|
||||
label = asset_editor.findChild(QtWidgets.QLabel, "textEdit")
|
||||
return helper.wait_for_condition(lambda: "*" not in label.text(), 3.0)
|
||||
|
||||
def expand_container_rows(object_name):
|
||||
children = container.findChildren(QtWidgets.QFrame, object_name)
|
||||
for child in children:
|
||||
check_box = child.findChild(QtWidgets.QCheckBox)
|
||||
if check_box and not check_box.isChecked():
|
||||
QtTest.QTest.mouseClick(check_box, QtCore.Qt.LeftButton, QtCore.Qt.NoModifier)
|
||||
|
||||
def node_palette_search(node_name):
|
||||
search_box.setText(node_name)
|
||||
helper.wait_for_condition(lambda: search_box.text() == node_name, 1.0)
|
||||
# Try clicking ENTER in search box multiple times
|
||||
for _ in range(10):
|
||||
QtTest.QTest.keyClick(search_box, QtCore.Qt.Key_Enter, QtCore.Qt.NoModifier)
|
||||
if pyside_utils.find_child_by_pattern(tree, {"text": node_name}) is not None:
|
||||
break
|
||||
|
||||
# 1) Open Asset Editor
|
||||
general.idle_enable(True)
|
||||
# Initially close the Asset Editor and then reopen to ensure we don't have any existing assets open
|
||||
general.close_pane("Asset Editor")
|
||||
general.open_pane("Asset Editor")
|
||||
helper.wait_for_condition(lambda: general.is_pane_visible("Asset Editor"), 5.0)
|
||||
|
||||
# 2) Initially create new Script Event file with one method
|
||||
initialize_asset_editor_qt_objects()
|
||||
action = pyside_utils.find_child_by_pattern(menu_bar, {"type": QtWidgets.QAction, "text": "Script Events"})
|
||||
action.trigger()
|
||||
result = helper.wait_for_condition(
|
||||
lambda: container.findChild(QtWidgets.QFrame, "Events") is not None
|
||||
and container.findChild(QtWidgets.QFrame, "Events").findChild(QtWidgets.QToolButton, "") is not None,
|
||||
3 * GENERAL_WAIT,
|
||||
)
|
||||
Report.result(Tests.new_event_created, result)
|
||||
# Add new method
|
||||
add_event = container.findChild(QtWidgets.QFrame, "Events").findChild(QtWidgets.QToolButton, "")
|
||||
add_event.click()
|
||||
result = helper.wait_for_condition(
|
||||
lambda: asset_editor_widget.findChild(QtWidgets.QFrame, "EventName") is not None, GENERAL_WAIT
|
||||
)
|
||||
Report.result(Tests.child_1_created, result)
|
||||
editor.AssetEditorWidgetRequestsBus(bus.Broadcast, "SaveAssetAs", FILE_PATH)
|
||||
|
||||
# 3) Verify if file is created and saved
|
||||
result = helper.wait_for_condition(lambda: os.path.exists(FILE_PATH), 3 * GENERAL_WAIT)
|
||||
Report.result(Tests.file_saved, result and save_file())
|
||||
|
||||
# 4) Add a new child element
|
||||
add_event = container.findChild(QtWidgets.QFrame, "Events").findChild(QtWidgets.QToolButton, "")
|
||||
add_event.click()
|
||||
result = helper.wait_for_condition(
|
||||
lambda: len(asset_editor_widget.findChildren(QtWidgets.QFrame, "EventName")) == 2, 2 * GENERAL_WAIT
|
||||
)
|
||||
Report.result(Tests.child_2_created, result)
|
||||
|
||||
# 5) Update MethodNames and save file, (update all Method names to make it easier to search in SC later)
|
||||
# Expand the EventName initially
|
||||
expand_container_rows("EventName")
|
||||
# Expand Name fields under it
|
||||
expand_container_rows("Name")
|
||||
count = 0 # 2 Method names will be updated Ex: test_method_name_0, test_method_name_1
|
||||
container = asset_editor_widget.findChild(QtWidgets.QWidget, "ContainerForRows")
|
||||
children = container.findChildren(QtWidgets.QFrame, "Name")
|
||||
for child in children:
|
||||
line_edit = child.findChild(QtWidgets.QLineEdit)
|
||||
if line_edit and line_edit.text() == "MethodName":
|
||||
line_edit.setText(f"{METHOD_NAME}_{count}")
|
||||
count += 1
|
||||
save_file()
|
||||
|
||||
# 6) Verify if the new node exist in SC (search in node palette)
|
||||
general.open_pane("Script Canvas")
|
||||
helper.wait_for_condition(lambda: general.is_pane_visible("Script Canvas"), 5.0)
|
||||
initialize_sc_qt_objects()
|
||||
node_palette_search(f"{METHOD_NAME}_1")
|
||||
get_node_index = lambda: pyside_utils.find_child_by_pattern(tree, {"text": f"{METHOD_NAME}_1"}) is not None
|
||||
result = helper.wait_for_condition(get_node_index, GENERAL_WAIT)
|
||||
Report.result(Tests.method_added, result)
|
||||
|
||||
# 7) Delete one method and save
|
||||
initialize_asset_editor_qt_objects()
|
||||
for child in container.findChildren(QtWidgets.QFrame, "EventName"):
|
||||
if child.findChild(QtWidgets.QToolButton, ""):
|
||||
child.findChild(QtWidgets.QToolButton, "").click()
|
||||
break
|
||||
save_file()
|
||||
|
||||
# 8) Verify if the node is removed in SC (search in node palette)
|
||||
initialize_sc_qt_objects()
|
||||
node_palette_search(f"{METHOD_NAME}_0")
|
||||
get_node_index = lambda: pyside_utils.find_child_by_pattern(tree, {"text": f"{METHOD_NAME}_0"}) is None
|
||||
result = helper.wait_for_condition(get_node_index, GENERAL_WAIT)
|
||||
Report.result(Tests.method_removed, result)
|
||||
|
||||
# 9) Close Asset Editor
|
||||
general.close_pane("Asset Editor")
|
||||
general.close_pane("Script Canvas")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import ImportPathHelper as imports
|
||||
|
||||
imports.init()
|
||||
from utils import Report
|
||||
|
||||
Report.start_test(ScriptEvent_AddRemoveMethod_UpdatesInSC)
|
||||
@@ -278,6 +278,7 @@ class TestScriptCanvasTests(object):
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
def test_Pane_PropertiesChanged_RetainsOnRestart(self, request, editor, config, project, launcher_platform):
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
@@ -289,3 +290,31 @@ class TestScriptCanvasTests(object):
|
||||
auto_test_mode=False,
|
||||
timeout=60,
|
||||
)
|
||||
|
||||
def test_ScriptEvent_AddRemoveMethod_UpdatesInSC(self, request, workspace, editor, launcher_platform):
|
||||
def teardown():
|
||||
file_system.delete(
|
||||
[os.path.join(workspace.paths.project(), "TestAssets", "test_file.scriptevents")], True, True
|
||||
)
|
||||
request.addfinalizer(teardown)
|
||||
file_system.delete(
|
||||
[os.path.join(workspace.paths.project(), "TestAssets", "test_file.scriptevents")], True, True
|
||||
)
|
||||
expected_lines = [
|
||||
"Success: New Script Event created",
|
||||
"Success: Initial Child Event created",
|
||||
"Success: Second Child Event created",
|
||||
"Success: Script event file saved",
|
||||
"Success: Method added to scriptevent file",
|
||||
"Success: Method removed from scriptevent file",
|
||||
]
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
TEST_DIRECTORY,
|
||||
editor,
|
||||
"ScriptEvent_AddRemoveMethod_UpdatesInSC.py",
|
||||
expected_lines,
|
||||
auto_test_mode=False,
|
||||
timeout=60,
|
||||
)
|
||||
|
||||
@@ -34,6 +34,7 @@ CGotoPositionDlg::CGotoPositionDlg(QWidget* pParent /*=NULL*/)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
setFixedSize(size());
|
||||
OnInitDialog();
|
||||
|
||||
auto doubleValueChanged = static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged);
|
||||
@@ -98,6 +99,9 @@ void CGotoPositionDlg::OnInitDialog()
|
||||
m_ui->m_dymSegX->setVisible(false);
|
||||
m_ui->m_dymSegY->setVisible(false);
|
||||
|
||||
// Ensure the goto button is highlighted correctly.
|
||||
m_ui->pushButton->setDefault(true);
|
||||
|
||||
OnUpdateNumbers();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,189 +6,210 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>358</width>
|
||||
<height>198</height>
|
||||
<width>290</width>
|
||||
<height>180</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Go to Position</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1,0,0,1,0,0,1">
|
||||
<item row="6" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="text">
|
||||
<string>Go To</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="3" colspan="2">
|
||||
<widget class="QPushButton" name="pushButton_2">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="6" colspan="2">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QDoubleSpinBox" name="m_dymZ"/>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QDoubleSpinBox" name="m_dymY"/>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="m_dymX"/>
|
||||
</item>
|
||||
<item row="4" column="4">
|
||||
<widget class="QDoubleSpinBox" name="m_dymAngleY"/>
|
||||
</item>
|
||||
<item row="3" column="4">
|
||||
<widget class="QDoubleSpinBox" name="m_dymAngleX"/>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Z:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Y:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="8">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Enter position here:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>X:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="8">
|
||||
<widget class="QLineEdit" name="m_posEdit">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Position:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>X:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="6">
|
||||
<widget class="QLabel" name="m_labelSegX">
|
||||
<property name="text">
|
||||
<string>X:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="4">
|
||||
<widget class="QDoubleSpinBox" name="m_dymAngleZ"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Y:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="6">
|
||||
<widget class="QLabel" name="m_labelSegY">
|
||||
<property name="text">
|
||||
<string>Y:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="3">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Z:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="5">
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="3" colspan="2">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Angles:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="6" colspan="2">
|
||||
<widget class="QLabel" name="m_labelSeg">
|
||||
<property name="text">
|
||||
<string>Segments:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="7">
|
||||
<widget class="QSpinBox" name="m_dymSegX"/>
|
||||
</item>
|
||||
<item row="4" column="7">
|
||||
<widget class="QSpinBox" name="m_dymSegY"/>
|
||||
</item>
|
||||
</layout>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1,0,0,1,0,0,1">
|
||||
<item row="5" column="6" colspan="2">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QDoubleSpinBox" name="m_dymZ"/>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QDoubleSpinBox" name="m_dymY"/>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="m_dymX"/>
|
||||
</item>
|
||||
<item row="4" column="4">
|
||||
<widget class="QDoubleSpinBox" name="m_dymAngleY"/>
|
||||
</item>
|
||||
<item row="3" column="4">
|
||||
<widget class="QDoubleSpinBox" name="m_dymAngleX"/>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Z:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Y:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="8">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Enter position here:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>X:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="8">
|
||||
<widget class="QLineEdit" name="m_posEdit">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Position:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>X:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="6">
|
||||
<widget class="QLabel" name="m_labelSegX">
|
||||
<property name="text">
|
||||
<string>X:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="4">
|
||||
<widget class="QDoubleSpinBox" name="m_dymAngleZ"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Y:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="6">
|
||||
<widget class="QLabel" name="m_labelSegY">
|
||||
<property name="text">
|
||||
<string>Y:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="3">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Z:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="5">
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="3" colspan="2">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Angles:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="6" colspan="2">
|
||||
<widget class="QLabel" name="m_labelSeg">
|
||||
<property name="text">
|
||||
<string>Segments:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="7">
|
||||
<widget class="QSpinBox" name="m_dymSegX"/>
|
||||
</item>
|
||||
<item row="4" column="7">
|
||||
<widget class="QSpinBox" name="m_dymSegY"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="buttonLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_1">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="text">
|
||||
<string>Go To</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_2">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>m_posEdit</tabstop>
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
#include <GemCatalog/GemCatalogScreen.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
#include <GemCatalog/GemSortFilterProxyModel.h>
|
||||
#include <GemCatalog/GemFilterWidget.h>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
@@ -25,15 +27,18 @@ namespace O3DE::ProjectManager
|
||||
: ScreenWidget(parent)
|
||||
{
|
||||
m_gemModel = new GemModel(this);
|
||||
GemSortFilterProxyModel* proxyModel = new GemSortFilterProxyModel(m_gemModel, this);
|
||||
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
vLayout->setMargin(0);
|
||||
vLayout->setSpacing(0);
|
||||
setLayout(vLayout);
|
||||
|
||||
QHBoxLayout* hLayout = new QHBoxLayout();
|
||||
hLayout->setMargin(0);
|
||||
vLayout->addLayout(hLayout);
|
||||
|
||||
m_gemListView = new GemListView(m_gemModel, this);
|
||||
m_gemListView = new GemListView(proxyModel, proxyModel->GetSelectionModel(), this);
|
||||
m_gemInspector = new GemInspector(m_gemModel, this);
|
||||
m_gemInspector->setFixedWidth(320);
|
||||
|
||||
@@ -56,8 +61,19 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
#endif
|
||||
|
||||
hLayout->addWidget(m_gemListView);
|
||||
GemFilterWidget* filterWidget = new GemFilterWidget(proxyModel);
|
||||
filterWidget->setFixedWidth(250);
|
||||
|
||||
QVBoxLayout* middleVLayout = new QVBoxLayout();
|
||||
middleVLayout->setMargin(0);
|
||||
middleVLayout->setSpacing(0);
|
||||
middleVLayout->addWidget(m_gemListView);
|
||||
|
||||
hLayout->addWidget(filterWidget);
|
||||
hLayout->addLayout(middleVLayout);
|
||||
hLayout->addWidget(m_gemInspector);
|
||||
|
||||
proxyModel->InvalidateFilter();
|
||||
}
|
||||
|
||||
QVector<GemInfo> GemCatalogScreen::GenerateTestData()
|
||||
@@ -73,10 +89,12 @@ namespace O3DE::ProjectManager
|
||||
gem.m_documentationLink = "http://www.amazon.com";
|
||||
gem.m_dependingGemUuids = QStringList({"EMotionFX", "Atom"});
|
||||
gem.m_conflictingGemUuids = QStringList({"Vegetation", "Camera", "ScriptCanvas", "CloudCanvas", "Networking"});
|
||||
gem.m_types = (GemInfo::Code | GemInfo::Asset);
|
||||
gem.m_version = "v1.01";
|
||||
gem.m_lastUpdatedDate = "24th April 2021";
|
||||
gem.m_binarySizeInKB = 40;
|
||||
gem.m_features = QStringList({"Animation", "Assets", "Physics"});
|
||||
gem.m_gemOrigin = GemInfo::O3DEFoundation;
|
||||
result.push_back(gem);
|
||||
|
||||
gem.m_name = "Atom";
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
|
||||
@@ -0,0 +1,412 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <GemCatalog/GemFilterWidget.h>
|
||||
#include <QButtonGroup>
|
||||
#include <QCheckBox>
|
||||
#include <QLabel>
|
||||
#include <QMap>
|
||||
#include <QLineEdit>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
FilterCategoryWidget::FilterCategoryWidget(const QString& header,
|
||||
const QVector<QString>& elementNames,
|
||||
const QVector<int>& elementCounts,
|
||||
bool showAllLessButton,
|
||||
int defaultShowCount,
|
||||
QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, m_defaultShowCount(defaultShowCount)
|
||||
{
|
||||
AZ_Assert(elementNames.size() == elementCounts.size(), "Number of element names needs to match the counts.");
|
||||
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
setLayout(vLayout);
|
||||
|
||||
// Collapse button
|
||||
QHBoxLayout* collapseLayout = new QHBoxLayout();
|
||||
m_collapseButton = new QPushButton();
|
||||
m_collapseButton->setCheckable(true);
|
||||
m_collapseButton->setFlat(true);
|
||||
m_collapseButton->setFocusPolicy(Qt::NoFocus);
|
||||
m_collapseButton->setFixedWidth(s_collapseButtonSize);
|
||||
m_collapseButton->setStyleSheet("border: 0px; border-radius: 0px;");
|
||||
connect(m_collapseButton, &QPushButton::clicked, this, [=]()
|
||||
{
|
||||
UpdateCollapseState();
|
||||
});
|
||||
collapseLayout->addWidget(m_collapseButton);
|
||||
|
||||
// Category title
|
||||
QLabel* headerLabel = new QLabel(header);
|
||||
headerLabel->setStyleSheet("font-size: 11pt;");
|
||||
collapseLayout->addWidget(headerLabel);
|
||||
vLayout->addLayout(collapseLayout);
|
||||
|
||||
vLayout->addSpacing(5);
|
||||
|
||||
// Everything in the main widget will be collapsed/uncollapsed
|
||||
{
|
||||
m_mainWidget = new QWidget();
|
||||
vLayout->addWidget(m_mainWidget);
|
||||
|
||||
QVBoxLayout* mainLayout = new QVBoxLayout();
|
||||
mainLayout->setMargin(0);
|
||||
mainLayout->setAlignment(Qt::AlignTop);
|
||||
m_mainWidget->setLayout(mainLayout);
|
||||
|
||||
// Elements
|
||||
m_buttonGroup = new QButtonGroup();
|
||||
m_buttonGroup->setExclusive(false);
|
||||
for (int i = 0; i < elementNames.size(); ++i)
|
||||
{
|
||||
QWidget* elementWidget = new QWidget();
|
||||
QHBoxLayout* elementLayout = new QHBoxLayout();
|
||||
elementLayout->setMargin(0);
|
||||
elementWidget->setLayout(elementLayout);
|
||||
|
||||
QCheckBox* checkbox = new QCheckBox(elementNames[i]);
|
||||
checkbox->setStyleSheet("font-size: 11pt;");
|
||||
m_buttonGroup->addButton(checkbox);
|
||||
elementLayout->addWidget(checkbox);
|
||||
|
||||
elementLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));
|
||||
|
||||
QLabel* countLabel = new QLabel(QString::number(elementCounts[i]));
|
||||
countLabel->setStyleSheet("font-size: 11pt; background-color: #333333; border-radius: 3px; color: #94D2FF;");
|
||||
elementLayout->addWidget(countLabel);
|
||||
|
||||
m_elementWidgets.push_back(elementWidget);
|
||||
mainLayout->addWidget(elementWidget);
|
||||
}
|
||||
|
||||
// See more / less
|
||||
if (showAllLessButton)
|
||||
{
|
||||
m_seeAllLessLabel = new LinkLabel();
|
||||
connect(m_seeAllLessLabel, &LinkLabel::clicked, this, [=]()
|
||||
{
|
||||
m_seeAll = !m_seeAll;
|
||||
UpdateSeeMoreLess();
|
||||
});
|
||||
mainLayout->addWidget(m_seeAllLessLabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
mainLayout->addSpacing(5);
|
||||
}
|
||||
}
|
||||
|
||||
// Separating line
|
||||
QFrame* hLine = new QFrame();
|
||||
hLine->setFrameShape(QFrame::HLine);
|
||||
hLine->setStyleSheet("color: #666666;");
|
||||
vLayout->addWidget(hLine);
|
||||
|
||||
UpdateCollapseState();
|
||||
UpdateSeeMoreLess();
|
||||
}
|
||||
|
||||
void FilterCategoryWidget::UpdateCollapseState()
|
||||
{
|
||||
if (m_collapseButton->isChecked())
|
||||
{
|
||||
m_collapseButton->setIcon(QIcon(":/Resources/ArrowDownLine.svg"));
|
||||
m_mainWidget->hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_collapseButton->setIcon(QIcon(":/Resources/ArrowUpLine.svg"));
|
||||
m_mainWidget->show();
|
||||
}
|
||||
}
|
||||
|
||||
void FilterCategoryWidget::UpdateSeeMoreLess()
|
||||
{
|
||||
if (!m_seeAllLessLabel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_elementWidgets.isEmpty())
|
||||
{
|
||||
m_seeAllLessLabel->hide();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_seeAllLessLabel->show();
|
||||
}
|
||||
|
||||
if (!m_seeAll)
|
||||
{
|
||||
m_seeAllLessLabel->setText("See all");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_seeAllLessLabel->setText("See less");
|
||||
}
|
||||
|
||||
int showCount = m_seeAll ? m_elementWidgets.size() : m_defaultShowCount;
|
||||
showCount = AZ::GetMin(showCount, m_elementWidgets.size());
|
||||
for (int i = 0; i < showCount; ++i)
|
||||
{
|
||||
m_elementWidgets[i]->show();
|
||||
}
|
||||
for (int i = showCount; i < m_elementWidgets.size(); ++i)
|
||||
{
|
||||
m_elementWidgets[i]->hide();
|
||||
}
|
||||
}
|
||||
|
||||
QButtonGroup* FilterCategoryWidget::GetButtonGroup()
|
||||
{
|
||||
return m_buttonGroup;
|
||||
}
|
||||
|
||||
GemFilterWidget::GemFilterWidget(GemSortFilterProxyModel* filterProxyModel, QWidget* parent)
|
||||
: QScrollArea(parent)
|
||||
, m_filterProxyModel(filterProxyModel)
|
||||
{
|
||||
m_gemModel = m_filterProxyModel->GetSourceModel();
|
||||
|
||||
setWidgetResizable(true);
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
|
||||
QWidget* mainWidget = new QWidget();
|
||||
setWidget(mainWidget);
|
||||
|
||||
m_mainLayout = new QVBoxLayout();
|
||||
m_mainLayout->setAlignment(Qt::AlignTop);
|
||||
mainWidget->setLayout(m_mainLayout);
|
||||
|
||||
QLabel* filterByLabel = new QLabel("Filter by");
|
||||
filterByLabel->setStyleSheet("font-size: 15pt;");
|
||||
m_mainLayout->addWidget(filterByLabel);
|
||||
|
||||
AddGemOriginFilter();
|
||||
AddTypeFilter();
|
||||
AddPlatformFilter();
|
||||
AddFeatureFilter();
|
||||
}
|
||||
|
||||
void GemFilterWidget::AddGemOriginFilter()
|
||||
{
|
||||
QVector<QString> elementNames;
|
||||
QVector<int> elementCounts;
|
||||
const int numGems = m_gemModel->rowCount();
|
||||
for (int originIndex = 0; originIndex < GemInfo::NumGemOrigins; ++originIndex)
|
||||
{
|
||||
const GemInfo::GemOrigin gemOriginToBeCounted = static_cast<GemInfo::GemOrigin>(1 << originIndex);
|
||||
|
||||
int gemOriginCount = 0;
|
||||
for (int gemIndex = 0; gemIndex < numGems; ++gemIndex)
|
||||
{
|
||||
const GemInfo::GemOrigin gemOrigin = m_gemModel->GetGemOrigin(m_gemModel->index(gemIndex, 0));
|
||||
|
||||
// Is the gem of the given origin?
|
||||
if (gemOriginToBeCounted == gemOrigin)
|
||||
{
|
||||
gemOriginCount++;
|
||||
}
|
||||
}
|
||||
|
||||
elementNames.push_back(GemInfo::GetGemOriginString(gemOriginToBeCounted));
|
||||
elementCounts.push_back(gemOriginCount);
|
||||
}
|
||||
|
||||
FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Provider", elementNames, elementCounts, /*showAllLessButton=*/false);
|
||||
m_mainLayout->addWidget(filterWidget);
|
||||
|
||||
const QList<QAbstractButton*> buttons = filterWidget->GetButtonGroup()->buttons();
|
||||
for (int i = 0; i < buttons.size(); ++i)
|
||||
{
|
||||
const GemInfo::GemOrigin gemOrigin = static_cast<GemInfo::GemOrigin>(1 << i);
|
||||
QAbstractButton* button = buttons[i];
|
||||
|
||||
connect(button, &QAbstractButton::toggled, this, [=](bool checked)
|
||||
{
|
||||
GemInfo::GemOrigins gemOrigins = m_filterProxyModel->GetGemOrigins();
|
||||
if (checked)
|
||||
{
|
||||
gemOrigins |= gemOrigin;
|
||||
}
|
||||
else
|
||||
{
|
||||
gemOrigins &= ~gemOrigin;
|
||||
}
|
||||
m_filterProxyModel->SetGemOrigins(gemOrigins);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void GemFilterWidget::AddTypeFilter()
|
||||
{
|
||||
QVector<QString> elementNames;
|
||||
QVector<int> elementCounts;
|
||||
const int numGems = m_gemModel->rowCount();
|
||||
for (int typeIndex = 0; typeIndex < GemInfo::NumTypes; ++typeIndex)
|
||||
{
|
||||
const GemInfo::Type type = static_cast<GemInfo::Type>(1 << typeIndex);
|
||||
|
||||
int typeGemCount = 0;
|
||||
for (int gemIndex = 0; gemIndex < numGems; ++gemIndex)
|
||||
{
|
||||
const GemInfo::Types types = m_gemModel->GetTypes(m_gemModel->index(gemIndex, 0));
|
||||
|
||||
// Is type (Asset, Code, Tool) part of the gem?
|
||||
if (types & type)
|
||||
{
|
||||
typeGemCount++;
|
||||
}
|
||||
}
|
||||
|
||||
elementNames.push_back(GemInfo::GetTypeString(type));
|
||||
elementCounts.push_back(typeGemCount);
|
||||
}
|
||||
|
||||
FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Type", elementNames, elementCounts, /*showAllLessButton=*/false);
|
||||
m_mainLayout->addWidget(filterWidget);
|
||||
|
||||
const QList<QAbstractButton*> buttons = filterWidget->GetButtonGroup()->buttons();
|
||||
for (int i = 0; i < buttons.size(); ++i)
|
||||
{
|
||||
const GemInfo::Type type = static_cast<GemInfo::Type>(1 << i);
|
||||
QAbstractButton* button = buttons[i];
|
||||
|
||||
connect(button, &QAbstractButton::toggled, this, [=](bool checked)
|
||||
{
|
||||
GemInfo::Types types = m_filterProxyModel->GetTypes();
|
||||
if (checked)
|
||||
{
|
||||
types |= type;
|
||||
}
|
||||
else
|
||||
{
|
||||
types &= ~type;
|
||||
}
|
||||
m_filterProxyModel->SetTypes(types);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void GemFilterWidget::AddPlatformFilter()
|
||||
{
|
||||
QVector<QString> elementNames;
|
||||
QVector<int> elementCounts;
|
||||
const int numGems = m_gemModel->rowCount();
|
||||
for (int platformIndex = 0; platformIndex < GemInfo::NumPlatforms; ++platformIndex)
|
||||
{
|
||||
const GemInfo::Platform platform = static_cast<GemInfo::Platform>(1 << platformIndex);
|
||||
|
||||
int platformGemCount = 0;
|
||||
for (int gemIndex = 0; gemIndex < numGems; ++gemIndex)
|
||||
{
|
||||
const GemInfo::Platforms platforms = m_gemModel->GetPlatforms(m_gemModel->index(gemIndex, 0));
|
||||
|
||||
// Is platform supported?
|
||||
if (platforms & platform)
|
||||
{
|
||||
platformGemCount++;
|
||||
}
|
||||
}
|
||||
|
||||
elementNames.push_back(GemInfo::GetPlatformString(platform));
|
||||
elementCounts.push_back(platformGemCount);
|
||||
}
|
||||
|
||||
FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Supported Platforms", elementNames, elementCounts, /*showAllLessButton=*/false);
|
||||
m_mainLayout->addWidget(filterWidget);
|
||||
|
||||
const QList<QAbstractButton*> buttons = filterWidget->GetButtonGroup()->buttons();
|
||||
for (int i = 0; i < buttons.size(); ++i)
|
||||
{
|
||||
const GemInfo::Platform platform = static_cast<GemInfo::Platform>(1 << i);
|
||||
QAbstractButton* button = buttons[i];
|
||||
|
||||
connect(button, &QAbstractButton::toggled, this, [=](bool checked)
|
||||
{
|
||||
GemInfo::Platforms platforms = m_filterProxyModel->GetPlatforms();
|
||||
if (checked)
|
||||
{
|
||||
platforms |= platform;
|
||||
}
|
||||
else
|
||||
{
|
||||
platforms &= ~platform;
|
||||
}
|
||||
m_filterProxyModel->SetPlatforms(platforms);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void GemFilterWidget::AddFeatureFilter()
|
||||
{
|
||||
// Alphabetically sorted, unique features and their number of occurrences in the gem database.
|
||||
QMap<QString, int> uniqueFeatureCounts;
|
||||
const int numGems = m_gemModel->rowCount();
|
||||
for (int gemIndex = 0; gemIndex < numGems; ++gemIndex)
|
||||
{
|
||||
const QStringList features = m_gemModel->GetFeatures(m_gemModel->index(gemIndex, 0));
|
||||
for (const QString& feature : features)
|
||||
{
|
||||
if (!uniqueFeatureCounts.contains(feature))
|
||||
{
|
||||
uniqueFeatureCounts.insert(feature, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
int& featureeCount = uniqueFeatureCounts[feature];
|
||||
featureeCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVector<QString> elementNames;
|
||||
QVector<int> elementCounts;
|
||||
for (auto iterator = uniqueFeatureCounts.begin(); iterator != uniqueFeatureCounts.end(); iterator++)
|
||||
{
|
||||
elementNames.push_back(iterator.key());
|
||||
elementCounts.push_back(iterator.value());
|
||||
}
|
||||
|
||||
FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Features", elementNames, elementCounts,
|
||||
/*showAllLessButton=*/true, /*defaultShowCount=*/5);
|
||||
m_mainLayout->addWidget(filterWidget);
|
||||
|
||||
const QList<QAbstractButton*> buttons = filterWidget->GetButtonGroup()->buttons();
|
||||
for (int i = 0; i < buttons.size(); ++i)
|
||||
{
|
||||
const QString& feature = elementNames[i];
|
||||
QAbstractButton* button = buttons[i];
|
||||
|
||||
connect(button, &QAbstractButton::toggled, this, [=](bool checked)
|
||||
{
|
||||
QSet<QString> features = m_filterProxyModel->GetFeatures();
|
||||
if (checked)
|
||||
{
|
||||
features.insert(feature);
|
||||
}
|
||||
else
|
||||
{
|
||||
features.remove(feature);
|
||||
}
|
||||
m_filterProxyModel->SetFeatures(features);
|
||||
});
|
||||
}
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <LinkWidget.h>
|
||||
#include <GemCatalog/GemSortFilterProxyModel.h>
|
||||
#include <QScrollArea>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <QCheckBox>
|
||||
#include <QVector>
|
||||
#include <QPushButton>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QButtonGroup)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class FilterCategoryWidget
|
||||
: public QWidget
|
||||
{
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
explicit FilterCategoryWidget(const QString& header,
|
||||
const QVector<QString>& elementNames,
|
||||
const QVector<int>& elementCounts,
|
||||
bool showAllLessButton = true,
|
||||
int defaultShowCount = 4,
|
||||
QWidget* parent = nullptr);
|
||||
|
||||
QButtonGroup* GetButtonGroup();
|
||||
|
||||
private:
|
||||
void UpdateCollapseState();
|
||||
void UpdateSeeMoreLess();
|
||||
|
||||
inline constexpr static int s_collapseButtonSize = 16;
|
||||
QPushButton* m_collapseButton = nullptr;
|
||||
|
||||
QWidget* m_mainWidget = nullptr;
|
||||
QButtonGroup* m_buttonGroup = nullptr;
|
||||
QVector<QWidget*> m_elementWidgets; //! Includes checkbox and the count labl.
|
||||
LinkLabel* m_seeAllLessLabel = nullptr;
|
||||
int m_defaultShowCount = 0;
|
||||
bool m_seeAll = false;
|
||||
};
|
||||
|
||||
class GemFilterWidget
|
||||
: public QScrollArea
|
||||
{
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
explicit GemFilterWidget(GemSortFilterProxyModel* filterProxyModel, QWidget* parent = nullptr);
|
||||
~GemFilterWidget() = default;
|
||||
|
||||
private:
|
||||
void AddGemOriginFilter();
|
||||
void AddTypeFilter();
|
||||
void AddPlatformFilter();
|
||||
void AddFeatureFilter();
|
||||
|
||||
QVBoxLayout* m_mainLayout = nullptr;
|
||||
GemModel* m_gemModel = nullptr;
|
||||
GemSortFilterProxyModel* m_filterProxyModel = nullptr;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -62,6 +62,19 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
}
|
||||
|
||||
QString GemInfo::GetGemOriginString(GemOrigin origin)
|
||||
{
|
||||
switch (origin)
|
||||
{
|
||||
case O3DEFoundation:
|
||||
return "Open 3D Foundation";
|
||||
case Local:
|
||||
return "Local";
|
||||
default:
|
||||
return "<Unknown Gem Origin>";
|
||||
}
|
||||
}
|
||||
|
||||
bool GemInfo::IsPlatformSupported(Platform platform) const
|
||||
{
|
||||
return (m_platforms & platform);
|
||||
|
||||
@@ -46,6 +46,15 @@ namespace O3DE::ProjectManager
|
||||
Q_DECLARE_FLAGS(Types, Type)
|
||||
static QString GetTypeString(Type type);
|
||||
|
||||
enum GemOrigin
|
||||
{
|
||||
O3DEFoundation = 1 << 0,
|
||||
Local = 1 << 1,
|
||||
NumGemOrigins = 2
|
||||
};
|
||||
Q_DECLARE_FLAGS(GemOrigins, GemOrigin)
|
||||
static QString GetGemOriginString(GemOrigin origin);
|
||||
|
||||
GemInfo() = default;
|
||||
GemInfo(const QString& name, const QString& creator, const QString& summary, Platforms platforms, bool isAdded);
|
||||
bool IsPlatformSupported(Platform platform) const;
|
||||
@@ -57,6 +66,7 @@ namespace O3DE::ProjectManager
|
||||
QString m_displayName;
|
||||
AZ::Uuid m_uuid;
|
||||
QString m_creator;
|
||||
GemOrigin m_gemOrigin = Local;
|
||||
bool m_isAdded = false; //! Is the gem currently added and enabled in the project?
|
||||
QString m_summary;
|
||||
Platforms m_platforms;
|
||||
@@ -74,3 +84,4 @@ namespace O3DE::ProjectManager
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(O3DE::ProjectManager::GemInfo::Platforms)
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(O3DE::ProjectManager::GemInfo::Types)
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(O3DE::ProjectManager::GemInfo::GemOrigins)
|
||||
|
||||
@@ -70,8 +70,8 @@ namespace O3DE::ProjectManager
|
||||
m_documentationLinkLabel->SetUrl(m_model->GetDocLink(modelIndex));
|
||||
|
||||
// Depending and conflicting gems
|
||||
m_dependingGems->Update("Depending Gems", "The following Gems will be automatically enabled with this Gem.", m_model->GetDependingGems(modelIndex));
|
||||
m_conflictingGems->Update("Conflicting Gems", "The following Gems will be automatically disabled with this Gem.", m_model->GetConflictingGems(modelIndex));
|
||||
m_dependingGems->Update("Depending Gems", "The following Gems will be automatically enabled with this Gem.", m_model->GetDependingGemNames(modelIndex));
|
||||
m_conflictingGems->Update("Conflicting Gems", "The following Gems will be automatically disabled with this Gem.", m_model->GetConflictingGemNames(modelIndex));
|
||||
|
||||
// Additional information
|
||||
m_versionLabel->setText(QString("Gem Version: %1").arg(m_model->GetVersion(modelIndex)));
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "GemItemDelegate.h"
|
||||
#include <GemCatalog/GemItemDelegate.h>
|
||||
#include "GemModel.h"
|
||||
#include <QEvent>
|
||||
#include <QPainter>
|
||||
@@ -18,9 +18,9 @@
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
GemItemDelegate::GemItemDelegate(GemModel* gemModel, QObject* parent)
|
||||
GemItemDelegate::GemItemDelegate(QAbstractItemModel* model, QObject* parent)
|
||||
: QStyledItemDelegate(parent)
|
||||
, m_gemModel(gemModel)
|
||||
, m_model(model)
|
||||
{
|
||||
AddPlatformIcon(GemInfo::Android, ":/Android.svg");
|
||||
AddPlatformIcon(GemInfo::iOS, ":/iOS.svg");
|
||||
@@ -78,7 +78,7 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
|
||||
// Gem name
|
||||
const QString gemName = m_gemModel->GetName(modelIndex);
|
||||
const QString gemName = GemModel::GetName(modelIndex);
|
||||
QFont gemNameFont(options.font);
|
||||
gemNameFont.setPixelSize(s_gemNameFontSize);
|
||||
gemNameFont.setBold(true);
|
||||
@@ -90,7 +90,7 @@ namespace O3DE::ProjectManager
|
||||
painter->drawText(gemNameRect, Qt::TextSingleLine, gemName);
|
||||
|
||||
// Gem creator
|
||||
const QString gemCreator = m_gemModel->GetCreator(modelIndex);
|
||||
const QString gemCreator = GemModel::GetCreator(modelIndex);
|
||||
QRect gemCreatorRect = GetTextRect(standardFont, gemCreator, s_fontSize);
|
||||
gemCreatorRect.moveTo(contentRect.left(), contentRect.top() + gemNameRect.height());
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace O3DE::ProjectManager
|
||||
painter->setFont(standardFont);
|
||||
painter->setPen(m_textColor);
|
||||
|
||||
const QString summary = m_gemModel->GetSummary(modelIndex);
|
||||
const QString summary = GemModel::GetSummary(modelIndex);
|
||||
painter->drawText(summaryRect, Qt::AlignLeft | Qt::TextWordWrap, summary);
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
void GemItemDelegate::DrawPlatformIcons(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const
|
||||
{
|
||||
const GemInfo::Platforms platforms = m_gemModel->GetPlatforms(modelIndex);
|
||||
const GemInfo::Platforms platforms = GemModel::GetPlatforms(modelIndex);
|
||||
int startX = 0;
|
||||
|
||||
// Iterate and draw the platforms in the order they are defined in the enum.
|
||||
@@ -188,7 +188,7 @@ namespace O3DE::ProjectManager
|
||||
QPoint circleCenter;
|
||||
QString buttonText;
|
||||
|
||||
const bool isAdded = m_gemModel->IsAdded(modelIndex);
|
||||
const bool isAdded = GemModel::IsAdded(modelIndex);
|
||||
if (isAdded)
|
||||
{
|
||||
painter->setBrush(m_buttonEnabledColor);
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <QStyledItemDelegate>
|
||||
#include "GemInfo.h"
|
||||
#include "GemModel.h"
|
||||
#include <QAbstractItemModel>
|
||||
#include <QHash>
|
||||
#endif
|
||||
|
||||
@@ -29,22 +29,13 @@ namespace O3DE::ProjectManager
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
explicit GemItemDelegate(GemModel* gemModel, QObject* parent = nullptr);
|
||||
explicit GemItemDelegate(QAbstractItemModel* model, QObject* parent = nullptr);
|
||||
~GemItemDelegate() = default;
|
||||
|
||||
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const override;
|
||||
bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) override;
|
||||
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const override;
|
||||
|
||||
private:
|
||||
void CalcRects(const QStyleOptionViewItem& option, const QModelIndex& modelIndex, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const;
|
||||
QRect GetTextRect(QFont& font, const QString& text, qreal fontSize) const;
|
||||
QRect CalcButtonRect(const QRect& contentRect) const;
|
||||
void DrawPlatformIcons(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const;
|
||||
void DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const;
|
||||
|
||||
GemModel* m_gemModel = nullptr;
|
||||
|
||||
// Colors
|
||||
const QColor m_textColor = QColor("#FFFFFF");
|
||||
const QColor m_linkColor = QColor("#94D2FF");
|
||||
@@ -71,6 +62,15 @@ namespace O3DE::ProjectManager
|
||||
inline constexpr static int s_buttonCircleRadius = s_buttonBorderRadius - 3;
|
||||
inline constexpr static qreal s_buttonFontSize = 12.0;
|
||||
|
||||
private:
|
||||
void CalcRects(const QStyleOptionViewItem& option, const QModelIndex& modelIndex, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const;
|
||||
QRect GetTextRect(QFont& font, const QString& text, qreal fontSize) const;
|
||||
QRect CalcButtonRect(const QRect& contentRect) const;
|
||||
void DrawPlatformIcons(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const;
|
||||
void DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const;
|
||||
|
||||
QAbstractItemModel* m_model = nullptr;
|
||||
|
||||
// Platform icons
|
||||
void AddPlatformIcon(GemInfo::Platform platform, const QString& iconPath);
|
||||
inline constexpr static int s_platformIconSize = 16;
|
||||
|
||||
@@ -18,17 +18,15 @@
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
GemListView::GemListView(GemModel* model, QWidget *parent) :
|
||||
QListView(parent)
|
||||
GemListView::GemListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent)
|
||||
: QListView(parent)
|
||||
{
|
||||
setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
|
||||
QPalette palette;
|
||||
palette.setColor(QPalette::Window, QColor("#333333"));
|
||||
setPalette(palette);
|
||||
setStyleSheet("background-color: #333333;");
|
||||
|
||||
setModel(model);
|
||||
setSelectionModel(model->GetSelectionModel());
|
||||
setSelectionModel(selectionModel);
|
||||
setItemDelegate(new GemItemDelegate(model, this));
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "GemInfo.h"
|
||||
#include "GemModel.h"
|
||||
#include <QAbstractItemModel>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QListView>
|
||||
#endif
|
||||
|
||||
@@ -24,8 +25,9 @@ namespace O3DE::ProjectManager
|
||||
: public QListView
|
||||
{
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
explicit GemListView(GemModel* model, QWidget *parent = nullptr);
|
||||
explicit GemListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent = nullptr);
|
||||
~GemListView() = default;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -36,11 +36,11 @@ namespace O3DE::ProjectManager
|
||||
const QString uuidString = gemInfo.m_uuid.ToString<AZStd::string>().c_str();
|
||||
item->setData(uuidString, RoleUuid);
|
||||
item->setData(gemInfo.m_creator, RoleCreator);
|
||||
item->setData(gemInfo.m_gemOrigin, RoleGemOrigin);
|
||||
item->setData(aznumeric_cast<int>(gemInfo.m_platforms), RolePlatforms);
|
||||
item->setData(aznumeric_cast<int>(gemInfo.m_types), RoleTypes);
|
||||
item->setData(gemInfo.m_summary, RoleSummary);
|
||||
item->setData(gemInfo.m_isAdded, RoleIsAdded);
|
||||
|
||||
item->setData(gemInfo.m_directoryLink, RoleDirectoryLink);
|
||||
item->setData(gemInfo.m_documentationLink, RoleDocLink);
|
||||
item->setData(gemInfo.m_dependingGemUuids, RoleDependingGems);
|
||||
@@ -48,12 +48,12 @@ namespace O3DE::ProjectManager
|
||||
item->setData(gemInfo.m_version, RoleVersion);
|
||||
item->setData(gemInfo.m_lastUpdatedDate, RoleLastUpdated);
|
||||
item->setData(gemInfo.m_binarySizeInKB, RoleBinarySize);
|
||||
|
||||
item->setData(gemInfo.m_features, RoleFeatures);
|
||||
|
||||
appendRow(item);
|
||||
|
||||
m_uuidToNameMap[uuidString] = gemInfo.m_displayName;
|
||||
const QModelIndex modelIndex = index(rowCount()-1, 0);
|
||||
m_uuidToIndexMap[uuidString] = modelIndex;
|
||||
}
|
||||
|
||||
void GemModel::Clear()
|
||||
@@ -71,6 +71,11 @@ namespace O3DE::ProjectManager
|
||||
return modelIndex.data(RoleCreator).toString();
|
||||
}
|
||||
|
||||
GemInfo::GemOrigin GemModel::GetGemOrigin(const QModelIndex& modelIndex)
|
||||
{
|
||||
return static_cast<GemInfo::GemOrigin>(modelIndex.data(RoleGemOrigin).toInt());
|
||||
}
|
||||
|
||||
QString GemModel::GetUuidString(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleUuid).toString();
|
||||
@@ -106,42 +111,63 @@ namespace O3DE::ProjectManager
|
||||
return modelIndex.data(RoleDocLink).toString();
|
||||
}
|
||||
|
||||
AZ::Outcome<QString> GemModel::FindGemNameByUuidString(const QString& uuidString) const
|
||||
QModelIndex GemModel::FindIndexByUuidString(const QString& uuidString) const
|
||||
{
|
||||
const auto iterator = m_uuidToNameMap.find(uuidString);
|
||||
if (iterator != m_uuidToNameMap.end())
|
||||
const auto iterator = m_uuidToIndexMap.find(uuidString);
|
||||
if (iterator != m_uuidToIndexMap.end())
|
||||
{
|
||||
return AZ::Success(iterator.value());
|
||||
return iterator.value();
|
||||
}
|
||||
|
||||
return AZ::Failure();
|
||||
return {};
|
||||
}
|
||||
|
||||
QStringList GemModel::GetDependingGems(const QModelIndex& modelIndex)
|
||||
void GemModel::FindGemNamesByUuidStrings(QStringList& inOutGemNames)
|
||||
{
|
||||
QStringList result = modelIndex.data(RoleDependingGems).toStringList();
|
||||
for (QString& dependingGemString : inOutGemNames)
|
||||
{
|
||||
QModelIndex modelIndex = FindIndexByUuidString(dependingGemString);
|
||||
if (modelIndex.isValid())
|
||||
{
|
||||
dependingGemString = GetName(modelIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QStringList GemModel::GetDependingGemUuids(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleDependingGems).toStringList();
|
||||
}
|
||||
|
||||
QStringList GemModel::GetDependingGemNames(const QModelIndex& modelIndex)
|
||||
{
|
||||
QStringList result = GetDependingGemUuids(modelIndex);
|
||||
if (result.isEmpty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
for (QString& dependingGemString : result)
|
||||
{
|
||||
AZ::Outcome<QString> gemNameOutcome = FindGemNameByUuidString(dependingGemString);
|
||||
if (gemNameOutcome.IsSuccess())
|
||||
{
|
||||
dependingGemString = gemNameOutcome.GetValue();
|
||||
}
|
||||
}
|
||||
|
||||
FindGemNamesByUuidStrings(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList GemModel::GetConflictingGems(const QModelIndex& modelIndex)
|
||||
QStringList GemModel::GetConflictingGemUuids(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleConflictingGems).toStringList();
|
||||
}
|
||||
|
||||
QStringList GemModel::GetConflictingGemNames(const QModelIndex& modelIndex)
|
||||
{
|
||||
QStringList result = GetConflictingGemUuids(modelIndex);
|
||||
if (result.isEmpty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
FindGemNamesByUuidStrings(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
QString GemModel::GetVersion(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleVersion).toString();
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <GemCatalog/GemInfo.h>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QStandardItemModel>
|
||||
@@ -34,11 +33,16 @@ namespace O3DE::ProjectManager
|
||||
void AddGem(const GemInfo& gemInfo);
|
||||
void Clear();
|
||||
|
||||
AZ::Outcome<QString> FindGemNameByUuidString(const QString& uuidString) const;
|
||||
QStringList GetDependingGems(const QModelIndex& modelIndex);
|
||||
QModelIndex FindIndexByUuidString(const QString& uuidString) const;
|
||||
void FindGemNamesByUuidStrings(QStringList& inOutGemNames);
|
||||
QStringList GetDependingGemUuids(const QModelIndex& modelIndex);
|
||||
QStringList GetDependingGemNames(const QModelIndex& modelIndex);
|
||||
QStringList GetConflictingGemUuids(const QModelIndex& modelIndex);
|
||||
QStringList GetConflictingGemNames(const QModelIndex& modelIndex);
|
||||
|
||||
static QString GetName(const QModelIndex& modelIndex);
|
||||
static QString GetCreator(const QModelIndex& modelIndex);
|
||||
static GemInfo::GemOrigin GetGemOrigin(const QModelIndex& modelIndex);
|
||||
static QString GetUuidString(const QModelIndex& modelIndex);
|
||||
static GemInfo::Platforms GetPlatforms(const QModelIndex& modelIndex);
|
||||
static GemInfo::Types GetTypes(const QModelIndex& modelIndex);
|
||||
@@ -46,7 +50,6 @@ namespace O3DE::ProjectManager
|
||||
static bool IsAdded(const QModelIndex& modelIndex);
|
||||
static QString GetDirectoryLink(const QModelIndex& modelIndex);
|
||||
static QString GetDocLink(const QModelIndex& modelIndex);
|
||||
static QStringList GetConflictingGems(const QModelIndex& modelIndex);
|
||||
static QString GetVersion(const QModelIndex& modelIndex);
|
||||
static QString GetLastUpdated(const QModelIndex& modelIndex);
|
||||
static int GetBinarySizeInKB(const QModelIndex& modelIndex);
|
||||
@@ -58,6 +61,7 @@ namespace O3DE::ProjectManager
|
||||
RoleName = Qt::UserRole,
|
||||
RoleUuid,
|
||||
RoleCreator,
|
||||
RoleGemOrigin,
|
||||
RolePlatforms,
|
||||
RoleSummary,
|
||||
RoleIsAdded,
|
||||
@@ -72,7 +76,7 @@ namespace O3DE::ProjectManager
|
||||
RoleTypes
|
||||
};
|
||||
|
||||
QHash<QString, QString> m_uuidToNameMap;
|
||||
QHash<QString, QModelIndex> m_uuidToIndexMap;
|
||||
QItemSelectionModel* m_selectionModel = nullptr;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <GemCatalog/GemSortFilterProxyModel.h>
|
||||
#include <QItemSelectionModel>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
GemSortFilterProxyModel::GemSortFilterProxyModel(GemModel* sourceModel, QObject* parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
, m_sourceModel(sourceModel)
|
||||
{
|
||||
setSourceModel(sourceModel);
|
||||
m_selectionProxyModel = new AzQtComponents::SelectionProxyModel(sourceModel->GetSelectionModel(), this, parent);
|
||||
}
|
||||
|
||||
bool GemSortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
|
||||
{
|
||||
// Do not use sourceParent->child because an invalid parent does not produce valid children (which our index function does)
|
||||
QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent);
|
||||
if (!sourceIndex.isValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_sourceModel->GetName(sourceIndex).contains(m_searchString, Qt::CaseInsensitive))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Gem origins
|
||||
if (m_gemOriginFilter)
|
||||
{
|
||||
bool supportsAnyFilteredGemOrigin = false;
|
||||
for (int i = 0; i < GemInfo::NumGemOrigins; ++i)
|
||||
{
|
||||
const GemInfo::GemOrigin filteredGemOrigin = static_cast<GemInfo::GemOrigin>(1 << i);
|
||||
if (m_gemOriginFilter & filteredGemOrigin)
|
||||
{
|
||||
if ((GemModel::GetGemOrigin(sourceIndex) == filteredGemOrigin))
|
||||
{
|
||||
supportsAnyFilteredGemOrigin = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!supportsAnyFilteredGemOrigin)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Platform
|
||||
if (m_platformFilter)
|
||||
{
|
||||
bool supportsAnyFilteredPlatform = false;
|
||||
for (int i = 0; i < GemInfo::NumPlatforms; ++i)
|
||||
{
|
||||
const GemInfo::Platform filteredPlatform = static_cast<GemInfo::Platform>(1 << i);
|
||||
if (m_platformFilter & filteredPlatform)
|
||||
{
|
||||
if ((GemModel::GetPlatforms(sourceIndex) & filteredPlatform))
|
||||
{
|
||||
supportsAnyFilteredPlatform = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!supportsAnyFilteredPlatform)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Types (Asset, Code, Tool)
|
||||
if (m_typeFilter)
|
||||
{
|
||||
bool supportsAnyFilteredType = false;
|
||||
for (int i = 0; i < GemInfo::NumTypes; ++i)
|
||||
{
|
||||
const GemInfo::Type filteredType = static_cast<GemInfo::Type>(1 << i);
|
||||
if (m_typeFilter & filteredType)
|
||||
{
|
||||
if ((GemModel::GetTypes(sourceIndex) & filteredType))
|
||||
{
|
||||
supportsAnyFilteredType = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!supportsAnyFilteredType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Features
|
||||
if (!m_featureFilter.isEmpty())
|
||||
{
|
||||
bool containsFilterFeature = false;
|
||||
const QStringList features = m_sourceModel->GetFeatures(sourceIndex);
|
||||
for (const QString& feature : features)
|
||||
{
|
||||
if (m_featureFilter.contains(feature))
|
||||
{
|
||||
containsFilterFeature = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!containsFilterFeature)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GemSortFilterProxyModel::InvalidateFilter()
|
||||
{
|
||||
invalidate();
|
||||
emit OnInvalidated();
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzQtComponents/Utilities/SelectionProxyModel.h>
|
||||
#include <GemCatalog/GemModel.h>
|
||||
#include <QtCore/QSortFilterProxyModel>
|
||||
#include <QSet>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QItemSelectionModel)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class GemSortFilterProxyModel
|
||||
: public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
GemSortFilterProxyModel(GemModel* sourceModel, QObject* parent = nullptr);
|
||||
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override;
|
||||
|
||||
GemModel* GetSourceModel() const { return m_sourceModel; }
|
||||
AzQtComponents::SelectionProxyModel* GetSelectionModel() const { return m_selectionProxyModel; }
|
||||
|
||||
void SetSearchString(const QString& searchString) { m_searchString = searchString; InvalidateFilter(); }
|
||||
|
||||
GemInfo::GemOrigins GetGemOrigins() const { return m_gemOriginFilter; }
|
||||
void SetGemOrigins(const GemInfo::GemOrigins& gemOrigins) { m_gemOriginFilter = gemOrigins; InvalidateFilter(); }
|
||||
|
||||
GemInfo::Platforms GetPlatforms() const { return m_platformFilter; }
|
||||
void SetPlatforms(const GemInfo::Platforms& platforms) { m_platformFilter = platforms; InvalidateFilter(); }
|
||||
|
||||
GemInfo::Types GetTypes() const { return m_typeFilter; }
|
||||
void SetTypes(const GemInfo::Types& types) { m_typeFilter = types; InvalidateFilter(); }
|
||||
|
||||
const QSet<QString>& GetFeatures() const { return m_featureFilter; }
|
||||
void SetFeatures(const QSet<QString>& features) { m_featureFilter = features; InvalidateFilter(); }
|
||||
|
||||
void InvalidateFilter();
|
||||
|
||||
signals:
|
||||
void OnInvalidated();
|
||||
|
||||
private:
|
||||
GemModel* m_sourceModel = nullptr;
|
||||
AzQtComponents::SelectionProxyModel* m_selectionProxyModel = nullptr;
|
||||
|
||||
QString m_searchString;
|
||||
GemInfo::GemOrigins m_gemOriginFilter = {};
|
||||
GemInfo::Platforms m_platformFilter = {};
|
||||
GemInfo::Types m_typeFilter = {};
|
||||
QSet<QString> m_featureFilter;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -32,8 +32,6 @@ namespace O3DE::ProjectManager
|
||||
layout->setSpacing(0);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
setFixedSize(this->geometry().width(), this->geometry().height());
|
||||
|
||||
m_pythonBindings = AZStd::make_unique<PythonBindings>(engineRootPath);
|
||||
|
||||
m_screensCtrl = new ScreensCtrl();
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
|
||||
@@ -57,6 +57,8 @@ set(FILES
|
||||
Source/TagWidget.cpp
|
||||
Source/GemCatalog/GemCatalogScreen.h
|
||||
Source/GemCatalog/GemCatalogScreen.cpp
|
||||
Source/GemCatalog/GemFilterWidget.h
|
||||
Source/GemCatalog/GemFilterWidget.cpp
|
||||
Source/GemCatalog/GemInfo.h
|
||||
Source/GemCatalog/GemInfo.cpp
|
||||
Source/GemCatalog/GemInspector.h
|
||||
@@ -67,4 +69,6 @@ set(FILES
|
||||
Source/GemCatalog/GemListView.cpp
|
||||
Source/GemCatalog/GemModel.h
|
||||
Source/GemCatalog/GemModel.cpp
|
||||
Source/GemCatalog/GemSortFilterProxyModel.h
|
||||
Source/GemCatalog/GemSortFilterProxyModel.cpp
|
||||
)
|
||||
|
||||
+3
@@ -47,6 +47,9 @@ namespace MaterialEditor
|
||||
//! @param distanceMax furthest camera can be from the target
|
||||
virtual void GetExtents(float& distanceMin, float& distanceMax) const = 0;
|
||||
|
||||
//! Get bounding sphere radius of the active model
|
||||
virtual float GetRadius() const = 0;
|
||||
|
||||
//! Reset camera to default position and rotation
|
||||
virtual void Reset() = 0;
|
||||
|
||||
|
||||
@@ -44,6 +44,8 @@ namespace MaterialEditor
|
||||
MaterialEditorViewportInputControllerRequestBus::BroadcastResult(
|
||||
m_targetPosition,
|
||||
&MaterialEditorViewportInputControllerRequestBus::Handler::GetTargetPosition);
|
||||
MaterialEditorViewportInputControllerRequestBus::BroadcastResult(
|
||||
m_radius, &MaterialEditorViewportInputControllerRequestBus::Handler::GetRadius);
|
||||
}
|
||||
|
||||
void Behavior::End()
|
||||
@@ -119,7 +121,8 @@ namespace MaterialEditor
|
||||
|
||||
float Behavior::GetSensitivityZ()
|
||||
{
|
||||
return 0.001f;
|
||||
// adjust zooming sensitivity by model size, so that large models zoom at the same speed as smaller ones
|
||||
return 0.001f * AZ::GetMax(0.5f, m_radius);
|
||||
}
|
||||
|
||||
AZ::Quaternion Behavior::LookRotation(AZ::Vector3 forward)
|
||||
|
||||
@@ -54,6 +54,8 @@ namespace MaterialEditor
|
||||
float m_y = 0;
|
||||
//! delta scroll wheel accumulated during current frame
|
||||
float m_z = 0;
|
||||
//! Model radius
|
||||
float m_radius = 1.0f;
|
||||
|
||||
AZ::EntityId m_cameraEntityId;
|
||||
AZ::Vector3 m_targetPosition = AZ::Vector3::CreateZero();
|
||||
|
||||
+7
-3
@@ -114,6 +114,11 @@ namespace MaterialEditor
|
||||
distanceMax = m_distanceMax;
|
||||
}
|
||||
|
||||
float MaterialEditorViewportInputController::GetRadius() const
|
||||
{
|
||||
return m_radius;
|
||||
}
|
||||
|
||||
void MaterialEditorViewportInputController::UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event)
|
||||
{
|
||||
if (m_keysChanged)
|
||||
@@ -306,11 +311,10 @@ namespace MaterialEditor
|
||||
if (modelAsset.IsReady())
|
||||
{
|
||||
const AZ::Aabb& aabb = modelAsset->GetAabb();
|
||||
float radius;
|
||||
aabb.GetAsSphere(m_modelCenter, radius);
|
||||
aabb.GetAsSphere(m_modelCenter, m_radius);
|
||||
|
||||
m_distanceMin = 0.5f * AZ::GetMin(AZ::GetMin(aabb.GetExtents().GetX(), aabb.GetExtents().GetY()), aabb.GetExtents().GetZ()) + DepthNear;
|
||||
m_distanceMax = radius * MaxDistanceMultiplier;
|
||||
m_distanceMax = m_radius * MaxDistanceMultiplier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -43,6 +43,7 @@ namespace MaterialEditor
|
||||
void SetTargetPosition(const AZ::Vector3& targetPosition) override;
|
||||
float GetDistanceToTarget() const override;
|
||||
void GetExtents(float& distanceMin, float& distanceMax) const override;
|
||||
float GetRadius() const override;
|
||||
void Reset() override;
|
||||
void SetFieldOfView(float value) override;
|
||||
bool IsCameraCentered() const override;
|
||||
@@ -96,6 +97,8 @@ namespace MaterialEditor
|
||||
float m_distanceMin = 1.0f;
|
||||
//! Maximum distance from camera to target
|
||||
float m_distanceMax = 10.0f;
|
||||
//! Model radius
|
||||
float m_radius = 1.0f;
|
||||
//! True if camera is centered on a model
|
||||
bool m_isCameraCentered = true;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user