mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-04 20:57:49 +00:00
1455 lines
44 KiB
C++
1455 lines
44 KiB
C++
/**
|
|
* UpdateUIManager.cpp
|
|
* Copyright (c) 2013 ROBLOX Corp. All rights reserved.
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "UpdateUIManager.h"
|
|
|
|
// Qt Headers
|
|
#include <QAction>
|
|
#include <QBitArray>
|
|
#include <QDateTime>
|
|
#include <QDockWidget>
|
|
#include <QScrollBar>
|
|
#include <QStatusBar>
|
|
#include <QLabel>
|
|
#include <QProgressBar>
|
|
#include <QWidgetAction>
|
|
#include <QRadioButton>
|
|
|
|
// Roblox Headers
|
|
#include "rbx/Log.h"
|
|
#include "rbx/TaskScheduler.h"
|
|
#include "v8datamodel/DataModel.h"
|
|
#include "v8datamodel/DebugSettings.h"
|
|
#include "v8datamodel/MouseCommand.h"
|
|
#include "v8datamodel/GameBasicSettings.h"
|
|
|
|
// Roblox Studio Headers
|
|
#include "AuthoringSettings.h"
|
|
#include "Roblox.h"
|
|
#include "RobloxContextualHelp.h"
|
|
#include "RobloxCustomWidgets.h"
|
|
#include "RobloxDiagnosticsView.h"
|
|
#include "RobloxDocManager.h"
|
|
#include "RobloxFindWidget.h"
|
|
#include "RobloxGameExplorer.h"
|
|
#include "RobloxMainWindow.h"
|
|
#include "RobloxPropertyWidget.h"
|
|
#include "RobloxScriptReview.h"
|
|
#include "RobloxSettings.h"
|
|
#include "RobloxTaskScheduler.h"
|
|
#include "RobloxTextOutputWidget.h"
|
|
#include "RobloxToolBox.h"
|
|
#include "RobloxTutorials.h"
|
|
#include "RobloxTreeWidget.h"
|
|
#include "CommonInsertWidget.h"
|
|
#include "RobloxIDEDoc.h"
|
|
#include "QtUtilities.h"
|
|
#include "AuthoringSettings.h"
|
|
#include "ScriptAnalysisWidget.h"
|
|
#include "RobloxTeamCreateWidget.h"
|
|
|
|
QString UpdateUIManager::defaultCommands =
|
|
"fileOpenAction fileNewAction fileExitAction aboutRobloxAction actionStartPage actionFullScreen "
|
|
"onlineHelpAction objectBrowserAction instanceDumpAction settingsAction openPluginsFolderAction "
|
|
"fastLogDumpAction filePublishedProjectsAction shortcutHelpAction managePluginsAction switchWindowsMenu resetViewAction __qtn_Quick_Access_Button "
|
|
"customizeQuickAccessAction viewCommandBarAction fileOpenRecentSavesAction ";
|
|
static QString kActionsThatBypassOnMenuShowStatusUpdates =
|
|
"publishGameAction";
|
|
// Added following actions if we want to support theme modification at runtime
|
|
// Office2007Blue Office2007Black Office2007Silver Office2007Aqua Windows7Scenic Office2010Blue Office2010Silver Office2010Black Office2013White Office2013Gray
|
|
bool UpdateUIManager::m_longProcessInProgress = false;
|
|
|
|
FASTFLAG(StudioShowTutorialsByDefault)
|
|
FASTFLAG(StudioSeparateActionByActivationMethod)
|
|
|
|
UpdateUIManager& UpdateUIManager::Instance()
|
|
{
|
|
static UpdateUIManager instance;
|
|
return instance;
|
|
}
|
|
|
|
UpdateUIManager::UpdateUIManager()
|
|
: m_pRobloxMainWindow(NULL)
|
|
, m_PauseStatusBar(0)
|
|
, m_isRunning(false)
|
|
, m_dockRestoreStates(eDW_MAX)
|
|
, m_BusyState(0)
|
|
{
|
|
}
|
|
|
|
UpdateUIManager::~UpdateUIManager()
|
|
{
|
|
}
|
|
|
|
void UpdateUIManager::saveDocksGeometry()
|
|
{
|
|
RobloxSettings settings;
|
|
for (int i = 0; i < eDW_MAX; i++)
|
|
{
|
|
EDockWindowID id = (EDockWindowID)i;
|
|
QDockWidget* dock = m_DockWidgets[id];
|
|
if (dock->widget())
|
|
settings.setValue(dock->objectName() + "/Geometry", dock->widget()->saveGeometry());
|
|
}
|
|
}
|
|
|
|
void UpdateUIManager::loadDocksGeometry()
|
|
{
|
|
RobloxSettings settings;
|
|
for (int i = 0; i < eDW_MAX; i++)
|
|
{
|
|
EDockWindowID id = (EDockWindowID)i;
|
|
QDockWidget* dock = m_DockWidgets[id];
|
|
QByteArray state = settings.value(dock->objectName() + "/Geometry").toByteArray();
|
|
if(!state.isEmpty() && dock->widget())
|
|
dock->widget()->restoreGeometry(state);
|
|
|
|
// force the layout to be updated to fix issues initializing detached on a second monitor
|
|
dock->layout()->update();
|
|
}
|
|
}
|
|
|
|
QWidget* UpdateUIManager::getExplorerWidget()
|
|
{
|
|
return m_ViewWidgets[eDW_OBJECT_EXPLORER];
|
|
}
|
|
|
|
QStackedWidget* UpdateUIManager::getChatWidgetStack()
|
|
{
|
|
if (m_ChatWidgetStack.isNull())
|
|
{
|
|
// we need to call this function in Main Thread only!
|
|
RBXASSERT(QThread::currentThread() == qApp->thread());
|
|
|
|
QDockWidget* dockWidget = new QDockWidget(tr("Chat"), m_pRobloxMainWindow);
|
|
dockWidget->setObjectName("chatDockWidget");
|
|
|
|
dockWidget->toggleViewAction()->setIcon(QIcon(":/RibbonBar/images/RibbonIcons/View/Chat.png"));
|
|
dockWidget->toggleViewAction()->setText(tr("Chat"));
|
|
dockWidget->toggleViewAction()->setStatusTip(tr("Chat"));
|
|
dockWidget->toggleViewAction()->setToolTip(tr("View Chat Window"));
|
|
|
|
// add a stack widget with an empty widget (to be shown show during play solo/non cloudedit mode)
|
|
m_ChatWidgetStack = new QStackedWidget(dockWidget);
|
|
m_ChatWidgetStack->addWidget(new QWidget);
|
|
|
|
dockWidget->setWidget(m_ChatWidgetStack);
|
|
configureDockWidget(dockWidget);
|
|
}
|
|
|
|
return m_ChatWidgetStack;
|
|
}
|
|
|
|
void UpdateUIManager::initDocks()
|
|
{
|
|
// TODO : convert this initialization stuff to a factory
|
|
|
|
m_DockData[eDW_DIAGNOSTICS] = SDockData(
|
|
UpdateUIManager::getAction("viewDiagnosticsAction"),
|
|
false );
|
|
|
|
m_DockData[eDW_TASK_SCHEDULER] = SDockData(
|
|
UpdateUIManager::getAction("viewTaskSchedulerAction"),
|
|
false );
|
|
|
|
m_DockData[eDW_TOOLBOX] = SDockData(
|
|
UpdateUIManager::getAction("viewToolboxAction"),
|
|
true );
|
|
|
|
m_DockData[eDW_TUTORIALS] = SDockData(
|
|
UpdateUIManager::getAction("viewTutorialsAction"),
|
|
false,
|
|
QSize(350, 300));
|
|
|
|
m_DockData[eDW_BASIC_OBJECTS] = SDockData(
|
|
UpdateUIManager::getAction("viewBasicObjectsAction"),
|
|
false );
|
|
|
|
m_DockData[eDW_SCRIPT_REVIEW] = SDockData(
|
|
UpdateUIManager::getAction("viewScriptPerformanceAction"),
|
|
false );
|
|
|
|
m_DockData[eDW_OBJECT_EXPLORER] = SDockData(
|
|
UpdateUIManager::getAction("viewObjectExplorerAction"),
|
|
true,
|
|
QSize(200, 300));
|
|
|
|
m_DockData[eDW_PROPERTIES] = SDockData(
|
|
UpdateUIManager::getAction("viewPropertiesAction"),
|
|
false,
|
|
QSize(200, 300));
|
|
|
|
m_DockData[eDW_OUTPUT] = SDockData(
|
|
UpdateUIManager::getAction("viewOutputWindowAction"),
|
|
false);
|
|
|
|
m_DockData[eDW_CONTEXTUAL_HELP] = SDockData(
|
|
UpdateUIManager::getAction("viewContextualHelpAction"),
|
|
false);
|
|
m_DockData[eDW_FIND] = SDockData(
|
|
UpdateUIManager::getAction("viewFindResultsWindowAction"),
|
|
false);
|
|
|
|
m_DockData[eDW_GAME_EXPLORER] = SDockData(
|
|
UpdateUIManager::getAction("gameExplorerAction"),
|
|
false);
|
|
|
|
m_DockData[eDW_SCRIPT_ANALYSIS] = SDockData(
|
|
UpdateUIManager::getAction("viewScriptAnalysisAction"),
|
|
false);
|
|
|
|
m_DockData[eDW_TEAM_CREATE] = SDockData(
|
|
UpdateUIManager::getAction("viewTeamCreateAction"),
|
|
false);
|
|
|
|
m_DockWidgets[eDW_DIAGNOSTICS] = m_pRobloxMainWindow->diagnosticsDockWidget;
|
|
m_DockWidgets[eDW_TASK_SCHEDULER] = m_pRobloxMainWindow->taskSchedulerDockWidget;
|
|
m_DockWidgets[eDW_TOOLBOX] = m_pRobloxMainWindow->toolBoxDockWidget;
|
|
m_DockWidgets[eDW_TUTORIALS] = m_pRobloxMainWindow->tutorialsDockWidget;
|
|
m_DockWidgets[eDW_BASIC_OBJECTS] = m_pRobloxMainWindow->basicObjectsDockWidget;
|
|
m_DockWidgets[eDW_SCRIPT_REVIEW] = m_pRobloxMainWindow->scriptReviewDockWidget;
|
|
m_DockWidgets[eDW_OBJECT_EXPLORER] = m_pRobloxMainWindow->objectExplorer;
|
|
m_DockWidgets[eDW_PROPERTIES] = m_pRobloxMainWindow->propertyBrowser;
|
|
m_DockWidgets[eDW_OUTPUT] = m_pRobloxMainWindow->outputWindow;
|
|
m_DockWidgets[eDW_CONTEXTUAL_HELP] = m_pRobloxMainWindow->contextualHelp;
|
|
m_DockWidgets[eDW_FIND] = m_pRobloxMainWindow->findResultsWindow;
|
|
m_DockWidgets[eDW_GAME_EXPLORER] = m_pRobloxMainWindow->gameExplorerDockWidget;
|
|
m_DockWidgets[eDW_SCRIPT_ANALYSIS] = m_pRobloxMainWindow->scriptAnalysisDockWidget;
|
|
m_DockWidgets[eDW_TEAM_CREATE] = m_pRobloxMainWindow->teamCreateDockWidget;
|
|
|
|
m_ViewWidgets[eDW_DIAGNOSTICS] = new RobloxDiagnosticsView();
|
|
m_ViewWidgets[eDW_TASK_SCHEDULER] = new RobloxTaskScheduler();
|
|
m_ViewWidgets[eDW_TOOLBOX] = new RobloxToolBox();
|
|
m_ViewWidgets[eDW_TUTORIALS] = new RobloxTutorials();
|
|
m_ViewWidgets[eDW_BASIC_OBJECTS] = new InsertObjectWidget(m_pRobloxMainWindow->basicObjectsDockWidget);
|
|
m_ViewWidgets[eDW_SCRIPT_REVIEW] = new RobloxScriptReview();
|
|
m_ViewWidgets[eDW_TEAM_CREATE] = new RobloxTeamCreateWidget(m_pRobloxMainWindow->teamCreateDockWidget);
|
|
|
|
m_ViewWidgets[eDW_OBJECT_EXPLORER] = new RobloxExplorerWidget(m_pRobloxMainWindow->objectExplorer);
|
|
|
|
m_ViewWidgets[eDW_PROPERTIES] = new RobloxPropertyWidget(m_pRobloxMainWindow->propertyBrowser);
|
|
m_ViewWidgets[eDW_OUTPUT] = m_pRobloxMainWindow->getOutputWidget();
|
|
m_ViewWidgets[eDW_CONTEXTUAL_HELP] = new RobloxContextualHelp();
|
|
m_ViewWidgets[eDW_FIND] = &RobloxFindWidget::singleton();
|
|
m_ViewWidgets[eDW_GAME_EXPLORER] = new RobloxGameExplorer(m_pRobloxMainWindow->gameExplorerDockWidget);
|
|
m_ViewWidgets[eDW_SCRIPT_ANALYSIS] = new ScriptAnalysisWidget(m_pRobloxMainWindow->scriptAnalysisDockWidget);
|
|
|
|
for ( int i = 0 ; i < eDW_MAX ; ++i )
|
|
{
|
|
EDockWindowID id = (EDockWindowID)i;
|
|
|
|
// Unfortunately we need to remove all the dockwidgets and re-add. If we don't we end up with a bug (DE5372)
|
|
m_pRobloxMainWindow->removeDockWidget(m_DockWidgets[id]);
|
|
if (id == eDW_BASIC_OBJECTS ||
|
|
id == eDW_DIAGNOSTICS ||
|
|
id == eDW_SCRIPT_REVIEW ||
|
|
id == eDW_TASK_SCHEDULER ||
|
|
id == eDW_TOOLBOX ||
|
|
id == eDW_CONTEXTUAL_HELP ||
|
|
id == eDW_GAME_EXPLORER ||
|
|
id == eDW_TUTORIALS ||
|
|
id == eDW_TEAM_CREATE)
|
|
{
|
|
m_pRobloxMainWindow->addDockWidget(Qt::LeftDockWidgetArea, m_DockWidgets[id]);
|
|
}
|
|
else if (id == eDW_PROPERTIES
|
|
|| id == eDW_OBJECT_EXPLORER)
|
|
{
|
|
m_pRobloxMainWindow->addDockWidget(Qt::RightDockWidgetArea, m_DockWidgets[id]);
|
|
}
|
|
else if (id == eDW_OUTPUT ||
|
|
id == eDW_FIND ||
|
|
id == eDW_SCRIPT_ANALYSIS)
|
|
{
|
|
m_pRobloxMainWindow->addDockWidget(Qt::BottomDockWidgetArea, m_DockWidgets[id]);
|
|
}
|
|
|
|
// make sure all the proper data and widgets were created
|
|
RBXASSERT(m_DockData.contains(id));
|
|
RBXASSERT(m_DockWidgets.contains(id));
|
|
RBXASSERT(!m_DockWidgets[id]->objectName().isEmpty());
|
|
RBXASSERT(m_ViewWidgets.contains(id));
|
|
RBXASSERT(!m_DockData[id].UpdateAction->objectName().isEmpty());
|
|
|
|
// hook up views to docks
|
|
if (m_ViewWidgets.contains(id))
|
|
m_DockWidgets[id]->setWidget(m_ViewWidgets[id]);
|
|
|
|
m_actionDockMap.insert(m_DockData[id].UpdateAction->objectName(), id);
|
|
|
|
// make sure we disconnect the original SLOT
|
|
QObject::disconnect(m_DockWidgets[id]->toggleViewAction(), SIGNAL(triggered(bool)), m_DockWidgets[id], SLOT(_q_toggleView(bool)));
|
|
// now connect toggleViewAction of dock widget with UpdateAction
|
|
QObject::connect(m_DockWidgets[id]->toggleViewAction(), SIGNAL(triggered(bool)), m_DockData[id].UpdateAction, SLOT(trigger()));
|
|
|
|
// Used to handle close event, etc.
|
|
m_DockWidgets[id]->installEventFilter(this);
|
|
}
|
|
}
|
|
|
|
void UpdateUIManager::init(RobloxMainWindow *pMainWindow)
|
|
{
|
|
if (!pMainWindow)
|
|
return;
|
|
|
|
m_pRobloxMainWindow = pMainWindow;
|
|
|
|
#ifdef _WIN32
|
|
if (!pMainWindow->isRibbonStyle()) // This fails for ribbon for some reason
|
|
qApp->setStyleSheet("QScrollBar { scrollbar-contextmenu: 0}");//remove scrollbar contextmenu from our application (this doesn't work for QWebView related scrollbars)
|
|
#endif
|
|
|
|
initDocks();
|
|
setupStatusBar();
|
|
setupSlots();
|
|
|
|
// Init our axisWidgets and 3d grid
|
|
pMainWindow->toggleAxisWidgetAction->setChecked(get3DAxisEnabled());
|
|
pMainWindow->toggle3DGridAction->setChecked(get3DGridEnabled());
|
|
|
|
m_isRunning = true;
|
|
|
|
#if WINVER >= 0x601
|
|
// initialize Vista/Win7 task bar interface
|
|
|
|
m_isTaskBarInitialized = false;
|
|
m_isIndeterminateProgress = false;
|
|
m_taskbar = NULL;
|
|
|
|
HRESULT hr = ::CoCreateInstance(
|
|
CLSID_TaskbarList,
|
|
0,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_PPV_ARGS(&m_taskbar) );
|
|
|
|
if ( hr == S_OK )
|
|
{
|
|
hr = m_taskbar->HrInit();
|
|
|
|
if ( hr == S_OK )
|
|
{
|
|
m_isTaskBarInitialized = true;
|
|
}
|
|
else
|
|
{
|
|
m_taskbar->Release();
|
|
m_taskbar = NULL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//update status bar
|
|
QTimer::singleShot(0, this, SLOT(updateStatusBar()));
|
|
}
|
|
|
|
void UpdateUIManager::setupStatusBar()
|
|
{
|
|
//don't create border for the permanent widgets
|
|
QStatusBar *pStatusBar = m_pRobloxMainWindow->statusBar();
|
|
if (!pStatusBar)
|
|
return;
|
|
|
|
pStatusBar->setStyleSheet("QStatusBar::item { border: none; } ");
|
|
|
|
//create labels to show different messages
|
|
m_pTaskSchedulerSBLabel = new QLabel;
|
|
m_pTimeSBLabel = new QLabel;
|
|
m_pCPUSBLabel = new QLabel;
|
|
m_pRAMSBLabel = new QLabel;
|
|
m_pFPSSBLabel = new QLabel;
|
|
|
|
m_pTaskSchedulerSBLabel->setMargin(5);
|
|
m_pTimeSBLabel->setMargin(5);
|
|
m_pCPUSBLabel->setMargin(5);
|
|
m_pRAMSBLabel->setMargin(5);
|
|
m_pFPSSBLabel->setMargin(5);
|
|
|
|
//add labels to statusbar
|
|
pStatusBar->addPermanentWidget(m_pTaskSchedulerSBLabel);
|
|
pStatusBar->addPermanentWidget(m_pTimeSBLabel);
|
|
pStatusBar->addPermanentWidget(m_pFPSSBLabel);
|
|
pStatusBar->addPermanentWidget(m_pCPUSBLabel);
|
|
pStatusBar->addPermanentWidget(m_pRAMSBLabel);
|
|
}
|
|
|
|
void UpdateUIManager::setMenubarEnabled(bool state)
|
|
{
|
|
QList<QMenu *> childMenus = m_pRobloxMainWindow->findChildren<QMenu *>();
|
|
for (int jj=0; jj < childMenus.size(); ++jj)
|
|
{
|
|
if ( state )
|
|
connect(childMenus.at(jj), SIGNAL(aboutToShow()), this, SLOT(onMenuShow()));
|
|
else
|
|
disconnect(childMenus.at(jj), SIGNAL(aboutToShow()), this, SLOT(onMenuShow()));
|
|
}
|
|
}
|
|
|
|
void UpdateUIManager::setupSlots()
|
|
{
|
|
QList<QMenu *> childMenus = m_pRobloxMainWindow->findChildren<QMenu *>();
|
|
for ( int j = 0; j < childMenus.size() ; ++j )
|
|
connect(childMenus.at(j),SIGNAL(aboutToShow()),this,SLOT(onMenuShow()));
|
|
|
|
connect(&m_pRobloxMainWindow->fillColorToolButton(),SIGNAL(frameShown()), this,SLOT(onMenuShow()));
|
|
connect(&m_pRobloxMainWindow->materialToolButton(),SIGNAL(frameShown()), this,SLOT(onMenuShow()));
|
|
}
|
|
|
|
QString UpdateUIManager::getDockGeometryKeyName(EDockWindowID dockId) const
|
|
{
|
|
return m_DockWidgets[dockId]->objectName() + "_geometry";
|
|
}
|
|
|
|
void UpdateUIManager::setDockVisibility(EDockWindowID dockId, bool visible)
|
|
{
|
|
if (m_ViewWidgets.contains(dockId))
|
|
m_ViewWidgets[dockId]->setVisible(visible);
|
|
|
|
m_DockWidgets[dockId]->setVisible(visible);
|
|
}
|
|
|
|
/**
|
|
* Sets up the view menu with the dock widget actions.
|
|
*
|
|
* @param insertBefore location to add the actions in the menu
|
|
*/
|
|
void UpdateUIManager::setupDockWidgetsViewMenu(QAction& insertBefore)
|
|
{
|
|
// Connect all dock widgets to their appropriate actions and add to the view menu
|
|
for ( int i = 0 ; i < eDW_MAX ; ++i )
|
|
{
|
|
EDockWindowID id = (EDockWindowID)i;
|
|
QAction& action = *m_DockData[id].UpdateAction;
|
|
|
|
// TODO : show view icons in menu
|
|
action.setIconVisibleInMenu(false);
|
|
|
|
m_pRobloxMainWindow->viewToolsToolBar->addAction(&action);
|
|
m_pRobloxMainWindow->menuView->insertAction(&insertBefore,&action);
|
|
}
|
|
}
|
|
|
|
void UpdateUIManager::shutDown()
|
|
{
|
|
m_isRunning = false;
|
|
|
|
#if WINVER >= 0x601
|
|
// delete Vista/Win7 task bar interface
|
|
if ( m_isTaskBarInitialized )
|
|
m_taskbar->Release();
|
|
#endif
|
|
}
|
|
|
|
void UpdateUIManager::onMenuShow()
|
|
{
|
|
IRobloxDoc *pDoc = RobloxDocManager::Instance().getCurrentDoc();
|
|
if (!pDoc)
|
|
return;
|
|
|
|
const QObject *pSender = sender();
|
|
if (!pSender)
|
|
return;
|
|
|
|
bool isTreeWidgetConextMenu = (pSender->parent() == m_pRobloxMainWindow->treeWidgetStack().currentWidget());
|
|
IRobloxDoc* playDoc = RobloxDocManager::Instance().getPlayDoc();
|
|
|
|
if (pSender->inherits("QMenu"))
|
|
{
|
|
QList<QAction*> menuActions = ((const QMenu *)pSender)->actions();
|
|
QAction *pAction = NULL;
|
|
bool checkedState = false, enabledState = false;
|
|
for (int i = 0; i < menuActions.size(); ++i)
|
|
{
|
|
pAction = menuActions.at(i);
|
|
|
|
if (!pAction)
|
|
continue;
|
|
|
|
QString objectName = pAction->objectName();
|
|
if (objectName.isEmpty())
|
|
continue;
|
|
|
|
if (kActionsThatBypassOnMenuShowStatusUpdates.contains(objectName))
|
|
continue;
|
|
|
|
if (defaultCommands.contains(objectName))
|
|
{
|
|
pAction->setEnabled(true);
|
|
}
|
|
else if (isTreeWidgetConextMenu && playDoc && playDoc->actionState(objectName, enabledState, checkedState))
|
|
{
|
|
pAction->setEnabled(enabledState);
|
|
pAction->setChecked(checkedState);
|
|
}
|
|
else if (pDoc->actionState(objectName, enabledState, checkedState))
|
|
{
|
|
pAction->setEnabled(enabledState);
|
|
pAction->setChecked(checkedState);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( isTreeWidgetConextMenu )
|
|
pDoc->handleAction("actionCustomContextMenuShow");
|
|
}
|
|
|
|
void UpdateUIManager::onMenuHide()
|
|
{
|
|
IRobloxDoc *pDoc = RobloxDocManager::Instance().getCurrentDoc();
|
|
if (!pDoc)
|
|
return;
|
|
|
|
const QObject *pSender = sender();
|
|
if(!pSender)
|
|
return;
|
|
|
|
if(!pSender->inherits("QMenu"))
|
|
return;
|
|
|
|
if (pSender->parent() == m_pRobloxMainWindow->treeWidgetStack().currentWidget())
|
|
pDoc->handleAction("actionCustomContextMenuHide");
|
|
}
|
|
|
|
void UpdateUIManager::setDefaultApplicationState()
|
|
{
|
|
QList<QAction*> allActions = m_pRobloxMainWindow->findChildren<QAction *>();
|
|
QAction *pAction = NULL;
|
|
|
|
for (int i = 0; i < allActions.size(); ++i)
|
|
{
|
|
pAction = allActions.at(i);
|
|
if (!pAction || pAction->objectName().isEmpty()
|
|
|| defaultCommands.contains(pAction->objectName())
|
|
|| pAction->objectName() == "executeScriptAction"
|
|
|| getDockActionNames().contains(pAction->objectName())) // docks are always enabled
|
|
continue;
|
|
|
|
pAction->setEnabled(false);
|
|
pAction->setChecked(false);
|
|
}
|
|
}
|
|
|
|
void UpdateUIManager::updateToolBars()
|
|
{
|
|
onToolBarsUpdate();
|
|
}
|
|
|
|
void UpdateUIManager::onToolBarsUpdate()
|
|
{
|
|
updateToolbarTask();
|
|
}
|
|
|
|
void UpdateUIManager::updateToolbarTask()
|
|
{
|
|
// update actions with shortcut, these need to be updated in both ribbon and menu
|
|
updateAction(*m_pRobloxMainWindow->deleteSelectedAction);
|
|
updateAction(*m_pRobloxMainWindow->selectAllAction);
|
|
updateAction(*m_pRobloxMainWindow->screenShotAction);
|
|
updateAction(*m_pRobloxMainWindow->pasteAction);
|
|
updateAction(*m_pRobloxMainWindow->pasteIntoAction);
|
|
|
|
updateAction(*m_pRobloxMainWindow->playSoloAction);
|
|
updateAction(*m_pRobloxMainWindow->startServerAction);
|
|
updateAction(*m_pRobloxMainWindow->startPlayerAction);
|
|
|
|
updateAction(*m_pRobloxMainWindow->findAction);
|
|
updateAction(*m_pRobloxMainWindow->replaceAction);
|
|
updateAction(*m_pRobloxMainWindow->findNextAction);
|
|
updateAction(*m_pRobloxMainWindow->findPreviousAction);
|
|
updateAction(*m_pRobloxMainWindow->goToLineAction);
|
|
|
|
updateAction(*m_pRobloxMainWindow->simulationPlayAction);
|
|
updateAction(*m_pRobloxMainWindow->simulationRunAction);
|
|
updateAction(*m_pRobloxMainWindow->simulationResetAction);
|
|
updateAction(*m_pRobloxMainWindow->simulationStopAction);
|
|
|
|
updateAction(*m_pRobloxMainWindow->rotateSelectionAction);
|
|
updateAction(*m_pRobloxMainWindow->zoomExtentsAction);
|
|
|
|
if (!m_pRobloxMainWindow->isRibbonStyle())
|
|
{
|
|
updateActions(m_pRobloxMainWindow->editCameraToolBar->actions());
|
|
updateActions(m_pRobloxMainWindow->runToolBar->actions());
|
|
updateActions(m_pRobloxMainWindow->advToolsToolBar->actions());
|
|
updateActions(m_pRobloxMainWindow->commandToolBar->actions());
|
|
updateActions(m_pRobloxMainWindow->menuTools->actions());
|
|
updateActions(m_pRobloxMainWindow->scriptMenu->actions());
|
|
updateActions(m_pRobloxMainWindow->standardToolBar->actions());
|
|
}
|
|
else
|
|
{
|
|
// Loop through every ribbon page, and group, and update all actions
|
|
const RibbonMainWindow* pMainWindow = static_cast<RibbonMainWindow*>(m_pRobloxMainWindow);
|
|
const int pagesCount = pMainWindow->ribbonBar()->getPageCount();
|
|
for (int i = 0; i < pagesCount; i++)
|
|
{
|
|
const QList<RibbonGroup*> ribbonGroups = pMainWindow->ribbonBar()->getPage(i)->findChildren<RibbonGroup*>();
|
|
for (int k = 0; k < ribbonGroups.count(); k++)
|
|
{
|
|
RibbonGroup* group = ribbonGroups[k];
|
|
|
|
const QList<RibbonGallery*> galleries = group->findChildren<RibbonGallery*>();
|
|
for (int j = 0; j < galleries.count(); j++)
|
|
{
|
|
const bool galleryEnabled = RobloxDocManager::Instance().getPlayDoc() != NULL;
|
|
galleries[j]->setEnabled(galleryEnabled);
|
|
}
|
|
|
|
updateActions(group->actions());
|
|
if (group->getOptionButtonAction() && group->getOptionButtonAction()->isVisible())
|
|
updateAction(*group->getOptionButtonAction());
|
|
}
|
|
}
|
|
|
|
// Update quickaccess bar's actions
|
|
if (pMainWindow->ribbonBar()->getQuickAccessBar())
|
|
updateActions(pMainWindow->ribbonBar()->getQuickAccessBar()->actions());
|
|
|
|
// Update all button groups, since they are not associated with an action
|
|
QList<QButtonGroup*> buttonGroups = pMainWindow->findChildren<QButtonGroup*>();
|
|
for (int ii=0; ii < buttonGroups.count(); ++ii)
|
|
modifyButtonGroupState(*buttonGroups.at(ii));
|
|
|
|
// Update all menu actions under ToolButtonProxyMenu
|
|
QList<ToolButtonProxyMenu*> toolButtonProxies = pMainWindow->findChildren<ToolButtonProxyMenu*>();
|
|
for (int ii=0; ii < toolButtonProxies.count(); ++ii)
|
|
updateActions(toolButtonProxies.at(ii)->actions());
|
|
|
|
updateAction(*m_pRobloxMainWindow->anchorAction); // Updated based on selection
|
|
}
|
|
}
|
|
|
|
void UpdateUIManager::updateActions(const QList<QAction*>& actions)
|
|
{
|
|
for (int i = 0; i < actions.size(); ++i)
|
|
{
|
|
QAction* action = actions.at(i);
|
|
updateAction(*action);
|
|
|
|
if ( action->inherits("QWidgetAction") )
|
|
{
|
|
QWidgetAction* widgetAction = static_cast<QWidgetAction*>(action);
|
|
QWidget* pDefaultWidget = widgetAction->defaultWidget();
|
|
if ( !pDefaultWidget )
|
|
continue;
|
|
|
|
if ( pDefaultWidget->inherits("QToolButton") )
|
|
{
|
|
QToolButton* button = static_cast<QToolButton*>(pDefaultWidget);
|
|
updateAction(*button->defaultAction());
|
|
}
|
|
else if ( pDefaultWidget->inherits("QRadioButton") )
|
|
{
|
|
QRadioButton* button = static_cast<QRadioButton*>(pDefaultWidget);
|
|
// Block all signals: Temporary Hack to fix Ribbon Bar slow down caused by the Radio buttons.
|
|
bool oldState = pDefaultWidget->blockSignals(true);
|
|
const QString buttonName = button->objectName();
|
|
QAction* action = m_pRobloxMainWindow->findChild<QAction*>(buttonName);
|
|
|
|
if (action)
|
|
{
|
|
updateAction(*action);
|
|
if (FFlag::StudioSeparateActionByActivationMethod)
|
|
{
|
|
button->setChecked(action->isChecked());
|
|
button->setEnabled(action->isEnabled());
|
|
}
|
|
}
|
|
|
|
// Unblock all signals: Temporary hack to fix Ribbon Bar slow down caused by Radio buttons.
|
|
pDefaultWidget->blockSignals(oldState);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void UpdateUIManager::updateAction(QAction& action)
|
|
{
|
|
if (action.objectName().isEmpty() )
|
|
return;
|
|
|
|
bool checkedState = action.isChecked();
|
|
bool enabledState = action.isEnabled();
|
|
|
|
// These commands should always be enabled
|
|
if ( UpdateUIManager::defaultCommands.contains(action.objectName()) )
|
|
{
|
|
modifyActionState(action,true,checkedState);
|
|
}
|
|
else
|
|
{
|
|
IRobloxDoc* pDoc = RobloxDocManager::Instance().getCurrentDoc();
|
|
if ( !pDoc )
|
|
{
|
|
// No current doc, disabled, but keep current checkedstate
|
|
modifyActionState(action, false, checkedState);
|
|
}
|
|
else if (pDoc->actionState(action.objectName(), enabledState, checkedState))
|
|
{
|
|
// pass on to current doc
|
|
modifyActionState(action, enabledState, checkedState);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UpdateUIManager::modifyActionState(QAction& action,bool enabledState,bool checkedState)
|
|
{
|
|
// force disabled if we're in a busy state
|
|
if ( UpdateUIManager::Instance().isBusy() )
|
|
enabledState = false;
|
|
|
|
m_pRobloxMainWindow->updateInternalWidgetsState(&action, enabledState, checkedState);
|
|
|
|
// don't spam if we're already configured properly
|
|
if ( action.isEnabled() == enabledState &&
|
|
(!action.isCheckable() || action.isChecked() == checkedState) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (QThread::currentThread() == thread())
|
|
{
|
|
action.setEnabled(enabledState);
|
|
action.setChecked(checkedState);
|
|
}
|
|
else
|
|
{
|
|
QMetaObject::invokeMethod(&action,"setEnabled",Qt::QueuedConnection,Q_ARG(bool,enabledState));
|
|
QMetaObject::invokeMethod(&action,"setChecked",Qt::QueuedConnection,Q_ARG(bool,checkedState));
|
|
}
|
|
}
|
|
|
|
void UpdateUIManager::modifyButtonGroupState(QButtonGroup &pButtonGroup)
|
|
{
|
|
bool checkedState = false;
|
|
bool enabledState = false;
|
|
|
|
IRobloxDoc* pDoc = RobloxDocManager::Instance().getCurrentDoc();
|
|
if (pDoc)
|
|
pDoc->actionState(pButtonGroup.objectName(), enabledState, checkedState);
|
|
|
|
QList<QAbstractButton *> buttons = pButtonGroup.buttons();
|
|
|
|
for (int ii=0; ii < buttons.count(); ++ii)
|
|
{
|
|
buttons.at(ii)->setEnabled(enabledState);
|
|
if (buttons.at(ii)->isCheckable())
|
|
{
|
|
if (QThread::currentThread() == thread())
|
|
{
|
|
buttons.at(ii)->setChecked(checkedState);
|
|
}
|
|
else
|
|
{
|
|
QMetaObject::invokeMethod(buttons.at(ii),"setChecked",Qt::QueuedConnection,Q_ARG(bool,checkedState));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool UpdateUIManager::toggleDockView(const QString& actionName)
|
|
{
|
|
QMap<QString, EDockWindowID>::iterator iter = m_actionDockMap.find(actionName);
|
|
if (iter == m_actionDockMap.end())
|
|
return false;
|
|
|
|
EDockWindowID id = iter.value();
|
|
|
|
if ( m_DockWidgets[id]->widget() != m_ViewWidgets[id] )
|
|
{
|
|
RBXASSERT(0);
|
|
m_DockWidgets[id]->setWidget(m_ViewWidgets[id]);
|
|
}
|
|
bool visibility1 = m_DockWidgets[id]->isVisible();
|
|
bool wasSetChecked = m_DockData[id].UpdateAction->isChecked();
|
|
setDockVisibility(id, wasSetChecked);
|
|
bool visibility2 = m_DockWidgets[id]->isVisible();
|
|
|
|
|
|
if (wasSetChecked)
|
|
m_DockWidgets[id]->raise();
|
|
|
|
if (visibility1 == visibility2)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Stops status bar updates.
|
|
* Increments pause state. Paused if pause state > 0.
|
|
*/
|
|
void UpdateUIManager::pauseStatusBarUpdate()
|
|
{
|
|
++m_PauseStatusBar;
|
|
}
|
|
|
|
#if WINVER >= 0x601
|
|
/**
|
|
* Synchronizes the task bar progress with the progress bar progress.
|
|
*/
|
|
void UpdateUIManager::configureTaskBar(QProgressBar* progressBar)
|
|
{
|
|
if ( !m_isTaskBarInitialized )
|
|
return;
|
|
|
|
m_taskProgressBar = progressBar;
|
|
|
|
if ( !progressBar )
|
|
{
|
|
m_taskbar->SetProgressState(m_pRobloxMainWindow->winId(),TBPF_NOPROGRESS);
|
|
return;
|
|
}
|
|
|
|
int min = progressBar->minimum();
|
|
int max = progressBar->maximum();
|
|
|
|
if ( min == max ) // indeterminate
|
|
{
|
|
m_isIndeterminateProgress = true;
|
|
m_taskbar->SetProgressState(m_pRobloxMainWindow->winId(),TBPF_INDETERMINATE);
|
|
}
|
|
else
|
|
{
|
|
m_isIndeterminateProgress = false;
|
|
m_taskbar->SetProgressState(m_pRobloxMainWindow->winId(),TBPF_NORMAL);
|
|
|
|
m_totalProgress = max - min; // convert to 0 to max
|
|
m_taskbar->SetProgressValue(m_pRobloxMainWindow->winId(),0,m_totalProgress);
|
|
}
|
|
}
|
|
#endif // WINVER
|
|
|
|
/**
|
|
* Change the cursor to the wait cursor and shut off some operations while busy.
|
|
* Only marked unbusy if busy state is 0. Each setBusy(true) must be followed by a
|
|
* setBusy(false) so the busy state will reach 0.
|
|
*/
|
|
void UpdateUIManager::setBusy(bool busy, bool useWaitCursor)
|
|
{
|
|
m_BusyState += busy ? 1 : -1;
|
|
|
|
m_pRobloxMainWindow->setUpdatesEnabled(false);
|
|
|
|
if ( m_BusyState == 1 && busy )
|
|
{
|
|
// only go into busy state 1 for the first time.
|
|
// if we go to 2+ then back to 1, we don't want to redo this code
|
|
|
|
if (useWaitCursor)
|
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
|
|
|
pauseStatusBarUpdate();
|
|
|
|
//save currently focused widget
|
|
m_BusyFocusWidget = QApplication::focusWidget();
|
|
|
|
// disable any menu updates
|
|
UpdateUIManager::Instance().setMenubarEnabled(false);
|
|
|
|
// disable widgets
|
|
m_pRobloxMainWindow->enableScriptCommandInput(false);
|
|
m_pRobloxMainWindow->centralWidget()->setEnabled(false);
|
|
|
|
// disable all actions
|
|
m_BusyEnabledActions.clear();
|
|
QList<QAction*> actions = m_pRobloxMainWindow->findChildren<QAction*>();
|
|
QList<QAction*>::iterator iter = actions.begin();
|
|
while ( iter != actions.end() )
|
|
{
|
|
QAction* action = *iter;
|
|
|
|
// only worry about actions with names
|
|
if ( !action->objectName().isEmpty() )
|
|
{
|
|
m_BusyEnabledActions[action] = action->isEnabled();
|
|
action->setEnabled(false);
|
|
}
|
|
|
|
++iter;
|
|
}
|
|
|
|
// disable the dock widgets
|
|
for ( int i = 0 ; i < eDW_MAX ; ++i )
|
|
{
|
|
const EDockWindowID id = (EDockWindowID)i;
|
|
m_DockWidgets[id]->setEnabled(false);
|
|
}
|
|
|
|
#if WINVER >= 0x601
|
|
// change task bar overlay icon to a busy icon
|
|
if ( m_isTaskBarInitialized )
|
|
{
|
|
QIcon icon = m_pRobloxMainWindow->style()->standardIcon(QStyle::SP_MessageBoxWarning);
|
|
|
|
HICON overlay_icon = icon.isNull() ? NULL : icon.pixmap(48).toWinHICON();
|
|
m_taskbar->SetOverlayIcon(m_pRobloxMainWindow->winId(),overlay_icon,L"Busy");
|
|
|
|
if ( overlay_icon )
|
|
::DestroyIcon(overlay_icon);
|
|
}
|
|
#endif
|
|
}
|
|
else if ( m_BusyState == 0 )
|
|
{
|
|
if (useWaitCursor)
|
|
QApplication::restoreOverrideCursor();
|
|
|
|
resumeStatusBarUpdate();
|
|
|
|
// enable menu updates
|
|
UpdateUIManager::Instance().setMenubarEnabled(true);
|
|
|
|
// enable widgets
|
|
m_pRobloxMainWindow->enableScriptCommandInput(true);
|
|
m_pRobloxMainWindow->centralWidget()->setEnabled(true);
|
|
|
|
// restore focus if we can, otherwise set to main window
|
|
// this fixes some focus issues on mac
|
|
m_pRobloxMainWindow->centralWidget()->setFocus();
|
|
if ( !m_BusyFocusWidget.isNull() )
|
|
m_BusyFocusWidget->setFocus();
|
|
else if ( QApplication::focusWidget() )
|
|
QApplication::focusWidget()->setFocus();
|
|
else
|
|
m_pRobloxMainWindow->setFocus();
|
|
m_BusyFocusWidget = NULL;
|
|
|
|
// enable all main actions
|
|
QList<QAction*> actions = m_BusyEnabledActions.keys();
|
|
QList<QAction*>::iterator iter = actions.begin();
|
|
while ( iter != actions.end() )
|
|
{
|
|
QAction* action = *iter;
|
|
action->setEnabled(m_BusyEnabledActions[action]);
|
|
++iter;
|
|
}
|
|
m_BusyEnabledActions.clear();
|
|
|
|
// enable the dock widgets
|
|
for ( int i = 0 ; i < eDW_MAX ; ++i )
|
|
{
|
|
const EDockWindowID id = (EDockWindowID)i;
|
|
m_DockWidgets[id]->setEnabled(true);
|
|
}
|
|
|
|
#if WINVER >= 0x601
|
|
// restore task bar overlay icon
|
|
if ( m_isTaskBarInitialized )
|
|
m_taskbar->SetOverlayIcon(m_pRobloxMainWindow->winId(),NULL,L"");
|
|
#endif
|
|
}
|
|
|
|
m_pRobloxMainWindow->setUpdatesEnabled(true);
|
|
}
|
|
|
|
/**
|
|
* Resumes the status bar updates.
|
|
* The pause state is decremented. Only at 0 will the status bar be updated.
|
|
*/
|
|
void UpdateUIManager::resumeStatusBarUpdate()
|
|
{
|
|
--m_PauseStatusBar;
|
|
if (m_isRunning && !m_PauseStatusBar)
|
|
QTimer::singleShot(200, this, SLOT(updateStatusBar()));
|
|
}
|
|
|
|
/**
|
|
* Creates a new progress bar and adds it to the status bar.
|
|
* If min == max then the progress bar is set to indeterminate.
|
|
* Synchronizes the task bar progress.
|
|
*
|
|
* @param message text message displayed in a label to the left
|
|
* @param min minimum progress bar value (start)
|
|
* @param max maximum progress bar value (end)
|
|
*/
|
|
QProgressBar* UpdateUIManager::showProgress(const QString& message,int min,int max)
|
|
{
|
|
QStatusBar* statusBar = m_pRobloxMainWindow->statusBar();
|
|
|
|
// configure progress bar widget
|
|
QProgressBar* progressBar = new QProgressBar(statusBar);
|
|
progressBar->setTextVisible(true);
|
|
progressBar->setMinimum(min);
|
|
progressBar->setMaximum(max);
|
|
progressBar->setValue(min);
|
|
|
|
// configure static label
|
|
QLabel* label = new QLabel(message,progressBar);
|
|
|
|
statusBar->setUpdatesEnabled(false);
|
|
statusBar->clearMessage();
|
|
statusBar->addWidget(label,0);
|
|
statusBar->addWidget(progressBar,1);
|
|
statusBar->setUpdatesEnabled(true);
|
|
|
|
// set up indeterminate if necessary
|
|
if ( min == max )
|
|
progressBar->setValue(-1);
|
|
|
|
m_ProgressBars.append(progressBar);
|
|
m_ProgressLabels.append(label);
|
|
|
|
// make sure they get rendered at least once
|
|
progressBar->show();
|
|
label->show();
|
|
|
|
#if WINVER >= 0x601
|
|
// sync task bar progress with progress bar
|
|
configureTaskBar(progressBar);
|
|
#endif
|
|
|
|
return progressBar;
|
|
}
|
|
|
|
/**
|
|
* Deletes the progress bar.
|
|
*/
|
|
void UpdateUIManager::hideProgress(QProgressBar* progressBar)
|
|
{
|
|
RBXASSERT(m_ProgressBars.contains(progressBar));
|
|
int index = m_ProgressBars.indexOf(progressBar);
|
|
if ( index != -1 )
|
|
{
|
|
delete m_ProgressBars[index];
|
|
m_ProgressBars.remove(index);
|
|
|
|
delete m_ProgressLabels[index];
|
|
m_ProgressLabels.remove(index);
|
|
}
|
|
|
|
#if WINVER >= 0x601
|
|
if ( m_isTaskBarInitialized )
|
|
{
|
|
// reset the "main" progress bar used to synchronize the task bar
|
|
if ( progressBar == m_taskProgressBar )
|
|
{
|
|
configureTaskBar(NULL);
|
|
if ( !m_ProgressBars.empty() )
|
|
configureTaskBar(m_ProgressBars.back());
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Updates the progress bar with a new value.
|
|
* If the value is -1 and the progress bar is indeterminate, update
|
|
* the indeterminate value.
|
|
* Synchronizes the task bar if this progress bar is the "main" one.
|
|
*/
|
|
void UpdateUIManager::updateProgress(QProgressBar* progressBar,int value)
|
|
{
|
|
RBXASSERT(progressBar);
|
|
|
|
// check for indeterminate and update
|
|
if ( value == -1 )
|
|
value = progressBar->value() + 1;
|
|
|
|
progressBar->setValue(value);
|
|
progressBar->update();
|
|
QApplication::processEvents();
|
|
|
|
#if WINVER >= 0x601
|
|
if ( progressBar == m_taskProgressBar )
|
|
{
|
|
// synchronize the task bar progress
|
|
if ( m_isTaskBarInitialized && !m_isIndeterminateProgress )
|
|
m_taskbar->SetProgressValue(m_pRobloxMainWindow->winId(),value,m_totalProgress);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* "Blocks" the main thread while a child thread is processed.
|
|
* The main thread can still handles events and GUI updates. This allows it to be
|
|
* responsive and update the progress bar. The application can set the state
|
|
* as "busy" to prevent reentrancy. Long running processes general lock resources and
|
|
* reentrancy will cause a deadlock.
|
|
*
|
|
* @param message message to display for the progress bar
|
|
* @param userWorkFunc long running function to run in a child thread
|
|
*/
|
|
void UpdateUIManager::waitForLongProcess(
|
|
const QString& message,
|
|
boost::function<void()> userWorkFunc )
|
|
{
|
|
QEventLoop eventLoop;
|
|
QMutex eventLoopMutex;
|
|
|
|
volatile bool done = false;
|
|
|
|
m_longProcessInProgress = true;
|
|
|
|
|
|
new boost::thread(
|
|
boost::bind(
|
|
&UpdateUIManager::exectueProgressFunction,
|
|
this,
|
|
userWorkFunc,
|
|
&eventLoop,
|
|
&eventLoopMutex,
|
|
(bool*)&done ) );
|
|
|
|
// wait for approx 300 ms, check if done and abort
|
|
// this avoids needing to show the progress and setting busy if the operation is fast
|
|
for ( int i = 0 ; i < 30 && !done ; i++ )
|
|
QtUtilities::sleep(10);
|
|
|
|
if ( !done )
|
|
{
|
|
setBusy(true);
|
|
QProgressBar* progressBar = showProgress(message);
|
|
|
|
// if still not done, then start the event loop
|
|
if ( !done )
|
|
{
|
|
QMutexLocker locker(&eventLoopMutex);
|
|
if ( !done )
|
|
eventLoop.exec();
|
|
}
|
|
|
|
hideProgress(progressBar);
|
|
setBusy(false);
|
|
}
|
|
m_longProcessInProgress = false;
|
|
}
|
|
|
|
/**
|
|
* Thread main for a progress function.
|
|
* Unblocks the main thread when done.
|
|
*/
|
|
void UpdateUIManager::exectueProgressFunction(
|
|
boost::function<void()> userWorkFunc,
|
|
QEventLoop* eventLoop,
|
|
QMutex* eventLoopMutex,
|
|
bool* done )
|
|
{
|
|
RBXASSERT(eventLoop);
|
|
RBXASSERT(eventLoopMutex);
|
|
RBXASSERT(done);
|
|
|
|
try
|
|
{
|
|
userWorkFunc();
|
|
}
|
|
catch(...)
|
|
{
|
|
RBXASSERT(false);
|
|
}
|
|
|
|
// check to see if the event loop is running
|
|
if ( eventLoopMutex->tryLock() )
|
|
{
|
|
// abort starting the event loop completely
|
|
*done = true;
|
|
eventLoopMutex->unlock();
|
|
}
|
|
else
|
|
{
|
|
// we're already executing or starting to execute, can't set done now
|
|
|
|
// wait until we really are executing
|
|
while ( !eventLoop->isRunning() )
|
|
QtUtilities::sleep(10);
|
|
|
|
// now shut it down since we know its running
|
|
eventLoop->exit();
|
|
}
|
|
}
|
|
|
|
void UpdateUIManager::commonContextMenuActions(QList<QAction *> &commonActions, bool insertIntoPasteMode)
|
|
{
|
|
commonActions.append(m_pRobloxMainWindow->cutAction);
|
|
commonActions.append(m_pRobloxMainWindow->copyAction);
|
|
commonActions.append(insertIntoPasteMode ? m_pRobloxMainWindow->pasteIntoAction : m_pRobloxMainWindow->pasteAction);
|
|
commonActions.append(m_pRobloxMainWindow->duplicateSelectionAction);
|
|
commonActions.append(m_pRobloxMainWindow->deleteSelectedAction);
|
|
commonActions.append(m_pRobloxMainWindow->renameObjectAction);
|
|
commonActions.append(NULL);
|
|
commonActions.append(m_pRobloxMainWindow->groupSelectionAction);
|
|
commonActions.append(m_pRobloxMainWindow->ungroupSelectionAction);
|
|
commonActions.append(m_pRobloxMainWindow->selectChildrenAction);
|
|
commonActions.append(m_pRobloxMainWindow->zoomExtentsAction);
|
|
|
|
commonActions.append(NULL);
|
|
commonActions.append(m_pRobloxMainWindow->insertIntoFileAction);
|
|
|
|
commonActions.append(NULL);
|
|
commonActions.append(m_pRobloxMainWindow->selectionSaveToFileAction);
|
|
commonActions.append(m_pRobloxMainWindow->saveToRobloxAction);
|
|
commonActions.append(m_pRobloxMainWindow->createNewLinkedSourceAction);
|
|
|
|
commonActions.append(m_pRobloxMainWindow->publishAsPluginAction);
|
|
commonActions.append(m_pRobloxMainWindow->exportSelectionAction);
|
|
}
|
|
|
|
void UpdateUIManager::updateStatusBar()
|
|
{
|
|
if (!AuthoringSettings::singleton().diagnosticsBarEnabled)
|
|
{
|
|
QString empty;
|
|
m_pTaskSchedulerSBLabel->setText(empty);
|
|
m_pCPUSBLabel->setText(empty);
|
|
m_pRAMSBLabel->setText(empty);
|
|
m_pTimeSBLabel->setText(empty);
|
|
m_pFPSSBLabel->setText(empty);
|
|
return;
|
|
}
|
|
|
|
const RBX::TaskScheduler& ts(RBX::TaskScheduler::singleton());
|
|
QString str;
|
|
str.sprintf(
|
|
"Sleep: %.1f Wait: %.1f Run: %.2f Affinity: %d%% Scheduler: %.0f/s %d%% SortFreq: %.0f/s ErrorCalc: %.0f/s",
|
|
ts.numSleepingJobs(),
|
|
ts.numWaitingJobs(),
|
|
ts.numRunningJobs(),
|
|
(int)(100.0 * ts.threadAffinity()),
|
|
ts.schedulerRate(),
|
|
(int)(100.0 * ts.getSchedulerDutyCyclePerThread()),
|
|
ts.getSortFrequency(),
|
|
ts.getErrorCalculationRate());
|
|
|
|
m_pTaskSchedulerSBLabel->setText(str);
|
|
|
|
// CPU label
|
|
double cores = RBX::DebugSettings::singleton().processCores();
|
|
QString coresStr;
|
|
coresStr.sprintf("Cores: %.1g", cores);
|
|
m_pCPUSBLabel->setText(coresStr);
|
|
|
|
// RAM Label
|
|
int mem = RBX::DebugSettings::singleton().privateWorkingSetBytes();
|
|
m_pRAMSBLabel->setText(RBX::Log::formatMem(mem).c_str());
|
|
|
|
IRobloxDoc *pDoc = RobloxDocManager::Instance().getCurrentDoc();
|
|
if (pDoc)
|
|
{
|
|
pDoc->handleAction("actionUpdateStatusBar");
|
|
}
|
|
|
|
if (m_isRunning && !m_PauseStatusBar)
|
|
QTimer::singleShot(200, this, SLOT(updateStatusBar()));
|
|
}
|
|
|
|
void UpdateUIManager::setStatusLabels(QString sTimeLabel, QString sFpsLabel)
|
|
{
|
|
m_pTimeSBLabel->setText(sTimeLabel);
|
|
m_pFPSSBLabel->setText(sFpsLabel);
|
|
}
|
|
|
|
void UpdateUIManager::onQuickInsertFocus()
|
|
{
|
|
RobloxIDEDoc* playDoc = RobloxDocManager::Instance().getPlayDoc();
|
|
if (!playDoc)
|
|
return;
|
|
|
|
getViewWidget<InsertObjectWidget>(eDW_BASIC_OBJECTS).startingQuickInsert(QApplication::focusWidget(),
|
|
!m_DockWidgets[eDW_BASIC_OBJECTS]->isVisible());
|
|
|
|
setDockVisibility(eDW_BASIC_OBJECTS, true);
|
|
|
|
m_DockWidgets[eDW_BASIC_OBJECTS]->raise();
|
|
|
|
m_ViewWidgets[eDW_BASIC_OBJECTS]->activateWindow();
|
|
m_ViewWidgets[eDW_BASIC_OBJECTS]->setFocus(Qt::ShortcutFocusReason);
|
|
}
|
|
|
|
void UpdateUIManager::filterExplorer()
|
|
{
|
|
m_ViewWidgets[eDW_OBJECT_EXPLORER]->setFocus(Qt::ShortcutFocusReason);
|
|
}
|
|
|
|
bool UpdateUIManager::eventFilter(QObject* watched, QEvent* evt)
|
|
{
|
|
// Capture dock widget closing and set checked to false
|
|
if((evt->type() == QEvent::Show || evt->type() == QEvent::Hide) && watched->inherits("QDockWidget"))
|
|
{
|
|
QString dockName = watched->objectName();
|
|
for (int i = 0; i < eDW_MAX; i++)
|
|
{
|
|
EDockWindowID id = (EDockWindowID)i;
|
|
if (m_DockWidgets[id]->objectName() == dockName)
|
|
m_DockData[id].UpdateAction->setChecked(m_DockWidgets[id]->isVisible());
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
QAction* UpdateUIManager::getAction(const QString &actionName)
|
|
{
|
|
QList<QAction*> allActions = m_pRobloxMainWindow->findChildren<QAction*>(actionName);
|
|
if (allActions.size())
|
|
return allActions.at(0);
|
|
return NULL;
|
|
}
|
|
|
|
QList<QString> UpdateUIManager::getDockActionNames() const
|
|
{
|
|
return m_actionDockMap.keys();
|
|
}
|
|
|
|
QAction* UpdateUIManager::getDockAction(const EDockWindowID id) const
|
|
{
|
|
return m_DockData[id].UpdateAction;
|
|
}
|
|
|
|
void UpdateUIManager::updateBuildMode()
|
|
{
|
|
eBuildMode buildMode = m_pRobloxMainWindow->getBuildMode();
|
|
|
|
m_pRobloxMainWindow->setUpdatesEnabled(false);
|
|
|
|
RobloxIDEDoc* playDoc = RobloxDocManager::Instance().getPlayDoc();
|
|
if ( playDoc )
|
|
{
|
|
playDoc->enableUndo(buildMode != BM_BASIC);
|
|
|
|
if ( buildMode == BM_BASIC )
|
|
RobloxDocManager::Instance().setPlayDocCentralWidget();
|
|
else
|
|
RobloxDocManager::Instance().restoreCentralWidget();
|
|
}
|
|
|
|
if ( buildMode == BM_BASIC )
|
|
{
|
|
// hide the dock widgets
|
|
for ( int i = 0 ; i < eDW_MAX ; ++i )
|
|
{
|
|
const EDockWindowID id = (EDockWindowID)i;
|
|
setDockVisibility(id,false);
|
|
}
|
|
|
|
// hide the toolbars
|
|
QObjectList objects = m_pRobloxMainWindow->children();
|
|
QObjectList::iterator iter = objects.begin();
|
|
for ( ; iter != objects.end() ; ++iter )
|
|
{
|
|
QToolBar* toolbar = dynamic_cast<QToolBar*>(*iter);
|
|
if ( toolbar )
|
|
toolbar->setVisible(false);
|
|
}
|
|
|
|
// hide menu and status
|
|
m_pRobloxMainWindow->menuBar()->setVisible(false);
|
|
m_pRobloxMainWindow->statusBar()->setVisible(false);
|
|
m_pRobloxMainWindow->setWindowState(Qt::WindowFullScreen);
|
|
}
|
|
else if ( buildMode == BM_ADVANCED )
|
|
{
|
|
// show menu and status
|
|
if (!m_pRobloxMainWindow->isRibbonStyle())
|
|
{
|
|
m_pRobloxMainWindow->menuBar()->setVisible(true);
|
|
m_pRobloxMainWindow->statusBar()->setVisible(true);
|
|
}
|
|
|
|
// reload layout - this will restore all docks and toolbars to previous state
|
|
//m_pRobloxMainWindow->loadApplicationStates();
|
|
//m_pRobloxMainWindow->show();
|
|
|
|
// show the dock view widgets
|
|
for ( int i = 0 ; i < eDW_MAX ; ++i )
|
|
{
|
|
const EDockWindowID id = (EDockWindowID)i;
|
|
if ( m_DockWidgets[id]->isVisible() && m_ViewWidgets[id])
|
|
m_ViewWidgets[id]->setVisible(true);
|
|
}
|
|
}
|
|
|
|
updateDockActionsCheckedStates();
|
|
m_pRobloxMainWindow->updateWindowTitle();
|
|
|
|
RBX::MouseCommand::enableAdvArrowTool(buildMode != BM_BASIC);
|
|
|
|
RBX::GameBasicSettings::singleton().setStudioMode(buildMode != BM_BASIC);
|
|
RBX::GameBasicSettings::singleton().setFullScreen(buildMode == BM_BASIC);
|
|
|
|
m_pRobloxMainWindow->setUpdatesEnabled(true);
|
|
}
|
|
|
|
void UpdateUIManager::updateDockActionsCheckedStates()
|
|
{
|
|
// Sets the actions to be checked if the dock widget is opened.
|
|
for ( int i = 0 ; i < eDW_MAX ; ++i )
|
|
{
|
|
EDockWindowID id = (EDockWindowID)i;
|
|
m_DockData[id].UpdateAction->setChecked(m_DockWidgets[id]->isVisible());
|
|
}
|
|
}
|
|
|
|
bool UpdateUIManager::get3DAxisEnabled()
|
|
{
|
|
RobloxSettings settings;
|
|
return settings.value("View_AxisWidget", false).toBool();
|
|
}
|
|
|
|
void UpdateUIManager::set3DAxisEnabled( bool value )
|
|
{
|
|
RobloxSettings settings;
|
|
return settings.setValue("View_AxisWidget", value);
|
|
}
|
|
|
|
bool UpdateUIManager::get3DGridEnabled()
|
|
{
|
|
RobloxSettings settings;
|
|
return settings.value("View_ZeroPlaneGrid", false).toBool();
|
|
}
|
|
|
|
void UpdateUIManager::set3DGridEnabled( bool value )
|
|
{
|
|
RobloxSettings settings;
|
|
return settings.setValue("View_ZeroPlaneGrid", value);
|
|
}
|
|
|
|
QDockWidget* UpdateUIManager::getDockWidget( EDockWindowID dockId )
|
|
{
|
|
return m_DockWidgets[dockId];
|
|
}
|
|
|
|
bool UpdateUIManager::isLongProcessInProgress()
|
|
{
|
|
return m_longProcessInProgress;
|
|
}
|
|
|
|
void UpdateUIManager::showErrorMessage(QString title, QString message)
|
|
{
|
|
QMessageBox::critical(&getMainWindow(), title, message);
|
|
}
|
|
|
|
void UpdateUIManager::configureDockWidget(QDockWidget* dockWidget)
|
|
{
|
|
if(!m_pRobloxMainWindow->restoreDockWidget(dockWidget))
|
|
m_pRobloxMainWindow->addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
|
|
|
|
if (!m_pRobloxMainWindow->isRibbonStyle())
|
|
{
|
|
m_pRobloxMainWindow->viewToolsToolBar->addAction(dockWidget->toggleViewAction());
|
|
}
|
|
else
|
|
{
|
|
if (RibbonPage* pPage = m_pRobloxMainWindow->ribbonBar()->findChild<RibbonPage*>("View"))
|
|
{
|
|
if (RibbonGroup* pGroup = pPage->findChild<RibbonGroup*>("Show"))
|
|
pGroup->addAction(dockWidget->toggleViewAction(), Qt::ToolButtonTextBesideIcon);
|
|
}
|
|
}
|
|
|
|
dockWidget->toggleViewAction()->setIconVisibleInMenu(false);
|
|
QObject::disconnect(dockWidget->toggleViewAction(), SIGNAL(triggered(bool)), dockWidget, SLOT(_q_toggleView(bool)));
|
|
QObject::connect(dockWidget->toggleViewAction(), SIGNAL(triggered(bool)), this, SLOT(updateActionWidgetVisibility()));
|
|
}
|
|
|
|
void UpdateUIManager::updateActionWidgetVisibility()
|
|
{
|
|
QAction* pAction = qobject_cast<QAction*>(sender());
|
|
if (!pAction || !pAction->parentWidget())
|
|
return;
|
|
|
|
pAction->parentWidget()->setVisible(pAction->isChecked());
|
|
if (pAction->isChecked())
|
|
pAction->parentWidget()->raise();
|
|
} |