Start: UX refinements

Start: Automatically run command when event loop starts
Also sets PartDesign as the default startup Workbench.
Start: Add checkbox for starting or not starting Start
Start: Correct default card size parameter access
Start: General cleanup
This commit is contained in:
Chris Hennes
2024-04-17 21:45:12 -05:00
parent 64bd9417a7
commit 4b32ab84ed
13 changed files with 413 additions and 18 deletions

View File

@@ -164,7 +164,7 @@ int main( int argc, char ** argv )
App::Application::Config()["AppIcon"] = "freecad";
App::Application::Config()["SplashScreen"] = "freecadsplash";
App::Application::Config()["AboutImage"] = "freecadabout";
App::Application::Config()["StartWorkbench"] = "NoneWorkbench";
App::Application::Config()["StartWorkbench"] = "PartDesignWorkbench";
//App::Application::Config()["HiddenDockWindow"] = "Property editor";
App::Application::Config()["SplashAlignment" ] = "Bottom|Left";
App::Application::Config()["SplashTextColor" ] = "#8aadf4"; // light blue

View File

@@ -21,6 +21,10 @@
# * *
# ***************************************************************************/
if( NOT EXISTS "${CMAKE_SOURCE_DIR}/src/3rdParty/GSL" )
message( SEND_ERROR "The C++ Guidelines Support Library (GSL) submodule is not available. Please run git submodule update --init" )
endif()
add_subdirectory(App)
set(Start_Scripts

View File

@@ -22,13 +22,17 @@
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QString>
#include <QTimer>
#endif
#include <Base/Console.h>
#include <Base/Interpreter.h>
#include <Base/PyObjectBase.h>
#include <Gui/Language/Translator.h>
#include <Gui/Command.h>
#include <QString>
#include <3rdParty/GSL/include/gsl/pointers>
@@ -60,6 +64,28 @@ public:
}
};
class StartLauncher
{
public:
StartLauncher()
{
// QTimers don't fire until the event loop starts, which is our signal that the GUI is up
QTimer::singleShot(1000, [this] {
Launch();
});
}
void Launch()
{
auto hGrp = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Start");
bool showOnStartup = hGrp->GetBool("ShowOnStartup", true);
if (showOnStartup) {
Gui::Application::Instance->commandManager().runCommandByName("Start_Start");
}
}
};
PyObject* initModule()
{
auto newModule = gsl::owner<Module*>(new Module);
@@ -71,6 +97,8 @@ PyObject* initModule()
/* Python entry */
PyMOD_INIT_FUNC(StartGui)
{
static StartGui::StartLauncher* launcher = new StartGui::StartLauncher();
Base::Console().Log("Loading GUI of Start module... ");
PyObject* mod = StartGui::initModule();
auto manipulator = std::make_shared<StartGui::Manipulator>();

View File

@@ -62,7 +62,8 @@ SET(StartGui_SRCS
)
SET(StartGuiIcon_SVG
Resources/icons/StartWorkbench.svg
Resources/icons/StartCommandIcon.svg
Resources/icons/PartDesignWorkbench.svg
)
# TODO: Evaluate PCH use with Qt6/QtQuick/Qml

View File

@@ -55,7 +55,7 @@ void FileCardDelegate::paint(QPainter* painter,
const QModelIndex& index) const
{
auto thumbnailSize =
static_cast<int>(_parameterGroup->GetInt("FileThumbnailIconsSize", 64)); // NOLINT
static_cast<int>(_parameterGroup->GetInt("FileThumbnailIconsSize", 128)); // NOLINT
auto cardWidth = thumbnailSize;
auto baseName = index.data(static_cast<int>(DisplayedFilesModelRoles::baseName)).toString();
auto size = index.data(static_cast<int>(DisplayedFilesModelRoles::size)).toString();
@@ -126,16 +126,14 @@ QPixmap pixmapToSizedQImage(const QImage& pixmap, int size)
QPixmap FileCardDelegate::generateThumbnail(const QString& path) const
{
auto thumbnailSize =
static_cast<int>(_parameterGroup->GetInt("FileThumbnailIconsSize", 64)); // NOLINT
static_cast<int>(_parameterGroup->GetInt("FileThumbnailIconsSize", 128)); // NOLINT
if (path.endsWith(QLatin1String(".fcstd"), Qt::CaseSensitivity::CaseInsensitive)) {
QImageReader reader(QLatin1String(":/icons/freecad-doc.svg"));
;
reader.setScaledSize({thumbnailSize, thumbnailSize});
return QPixmap::fromImage(reader.read());
}
if (path.endsWith(QLatin1String(".fcmacro"), Qt::CaseSensitivity::CaseInsensitive)) {
QImageReader reader(QLatin1String(":/icons/MacroEditor.svg"));
;
reader.setScaledSize({thumbnailSize, thumbnailSize});
return QPixmap::fromImage(reader.read());
}

View File

@@ -49,7 +49,7 @@ CmdStart::CmdStart()
sToolTipText = QT_TR_NOOP("Displays the Start in an MDI view");
sWhatsThis = "Start_Start";
sStatusTip = sToolTipText;
sPixmap = "StartWorkbench";
sPixmap = "StartCommandIcon";
}
void CmdStart::activated(int iMsg)

View File

@@ -43,6 +43,7 @@
#include <unordered_map>
// Qt
#include <QCheckBox>
#include <QCoreApplication>
#include <QFile>
#include <QFileIconProvider>
@@ -56,7 +57,9 @@
#include <QPushButton>
#include <QScrollArea>
#include <QSpacerItem>
#include <QString>
#include <QStyleOptionViewItem>
#include <QTimer>
#include <QUrl>
#include <QVBoxLayout>
#include <QWidget>

View File

@@ -1,5 +1,6 @@
<RCC>
<qresource prefix="/">
<file>icons/StartWorkbench.svg</file>
<file>icons/StartCommandIcon.svg</file>
<file>icons/PartDesignWorkbench.svg</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,322 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64"
height="64"
id="svg3559"
version="1.1"
inkscape:version="0.91+devel+osxmenu r12922"
sodipodi:docname="PartDesign_Body.svg"
viewBox="0 0 64 64">
<defs
id="defs3561">
<linearGradient
inkscape:collect="always"
id="linearGradient4393">
<stop
style="stop-color:#204a87;stop-opacity:1"
offset="0"
id="stop4395" />
<stop
style="stop-color:#3465a4;stop-opacity:1"
offset="1"
id="stop4397" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4383">
<stop
style="stop-color:#3465a4;stop-opacity:1"
offset="0"
id="stop4385" />
<stop
style="stop-color:#729fcf;stop-opacity:1"
offset="1"
id="stop4387" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4383"
id="linearGradient4389"
x1="20.243532"
y1="37.588112"
x2="17.243532"
y2="27.588112"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-1.243533,-2.588112)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4393"
id="linearGradient4399"
x1="48.714352"
y1="45.585785"
x2="44.714352"
y2="34.585785"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(1.2856487,1.4142136)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4383-3"
id="linearGradient4389-0"
x1="27.243532"
y1="54.588112"
x2="21.243532"
y2="30.588112"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-1.243533,-2.588112)" />
<linearGradient
inkscape:collect="always"
id="linearGradient4383-3">
<stop
style="stop-color:#3465a4;stop-opacity:1"
offset="0"
id="stop4385-1" />
<stop
style="stop-color:#729fcf;stop-opacity:1"
offset="1"
id="stop4387-2" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4393-9"
id="linearGradient4399-7"
x1="48.714352"
y1="45.585785"
x2="40.714352"
y2="24.585787"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(1.2856487,1.4142136)" />
<linearGradient
inkscape:collect="always"
id="linearGradient4393-9">
<stop
style="stop-color:#204a87;stop-opacity:1"
offset="0"
id="stop4395-8" />
<stop
style="stop-color:#3465a4;stop-opacity:1"
offset="1"
id="stop4397-1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4393"
id="linearGradient69042"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-12.714351,-17.585786)"
x1="48.714352"
y1="45.585785"
x2="44.714352"
y2="34.585785" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4383"
id="linearGradient69056"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-1.243533,-2.588112)"
x1="27.243532"
y1="54.588112"
x2="17.243532"
y2="27.588112" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="10.941048"
inkscape:cx="31.005637"
inkscape:cy="29.259294"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1680"
inkscape:window-height="939"
inkscape:window-x="0"
inkscape:window-y="23"
inkscape:window-maximized="0"
inkscape:snap-global="true">
<inkscape:grid
type="xygrid"
id="grid3007"
empspacing="2"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata3564">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:title>Path-Stock</dc:title>
<dc:date>2015-07-04</dc:date>
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/Path/Gui/Resources/icons/Path-Stock.svg</dc:identifier>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title>[agryson] Alexander Gryson</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<path
style="fill:url(#linearGradient69056);fill-opacity:1;fill-rule:nonzero;stroke:#0b1521;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
d="m 9,49 0,-28 14,5 0,14 14,5 0,14 z"
id="path4381"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
<path
style="fill:url(#linearGradient4399);fill-opacity:1;fill-rule:nonzero;stroke:#0b1521;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
d="M 37,59 37,45 55,28 55,41 Z"
id="path4391"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:#0b1521;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
d="M 9,21 29,5 42,10 23,26 Z"
id="path4403"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
d="M 11.008035,47.60627 11,24 l 10,4 0,13 14,5 0.0081,10.184812 z"
id="path4381-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
<path
style="fill:none;stroke:#3465a4;stroke-width:2;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
d="M 39.005041,54.16825 39,46 53,33 l 0.0021,7.176847 z"
id="path4391-0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path69038"
d="M 23,40 42,23 55,28 37,45 Z"
style="fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:#0b1521;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path69040"
d="M 23,40 23,26 42,10 42,23 Z"
style="fill:url(#linearGradient69042);fill-opacity:1;fill-rule:nonzero;stroke:#0b1521;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path69044"
d="m 25,36 0,-9 15,-13 0,8 z"
style="fill:none;stroke:#3465a4;stroke-width:2;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="temporal"
style="display:none;opacity:0.58800001"
sodipodi:insensitive="true">
<path
inkscape:connector-curvature="0"
id="path68967"
d="M 9,35 9,49"
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
id="path68971"
d="M 9,35 37,45"
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="cc"
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 55,28 0,13"
id="path68973"
inkscape:connector-curvature="0" />
<path
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 37,45 55,28"
id="path68977"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path68983"
d="M 23,40 23,26"
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path68985"
d="m 29,5 13,5"
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 23,26 42,10"
id="path68989"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 19,13 29,5"
id="path68993"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 55,15 -9,8"
id="path68997"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path69030"
d="M 42,23 42,10"
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 42,23 14,5"
id="path69034"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path69036"
d="M 23,40 42,23"
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -25,6 +25,7 @@
#ifndef _PreComp_
#include <QCoreApplication>
#include <QCheckBox>
#include <QGridLayout>
#include <QLabel>
#include <QListView>
@@ -112,13 +113,25 @@ StartView::StartView(Gui::Document* pcDocument, QWidget* parent)
// New WB notice: temporary to explain why all your setting disappeared
auto newStartWBNotice = gsl::owner<QLabel*>(
new QLabel(tr("NOTE: The Start Workbench has been completely rewritten to remove all "
"network access, and to remove "
"its dependency on Chromium. This is still a work-in-progress, and not all "
"settings from the previous "
"version of Start have been migrated yet.")));
"network access, and to remove its dependency on Chromium. This is still a "
"work-in-progress, and not all settings from the previous version of Start "
"have been migrated yet.")));
newStartWBNotice->setWordWrap(true);
layout->addWidget(newStartWBNotice);
// Launch start automatically?
QString application = QString::fromUtf8(App::Application::Config()["ExeName"].c_str());
auto launchAutomaticallyCheckbox =
gsl::owner<QCheckBox*>(new QCheckBox(tr("Show Start when starting %1").arg(application)));
bool showOnStartup = hGrp->GetBool("ShowOnStartup", true);
launchAutomaticallyCheckbox->setCheckState(showOnStartup ? Qt::CheckState::Checked
: Qt::CheckState::Unchecked);
connect(launchAutomaticallyCheckbox,
&QCheckBox::toggled,
this,
&StartView::showOnStartupChanged);
layout->addWidget(launchAutomaticallyCheckbox);
const QLatin1String h1Start("<h1>");
const QLatin1String h1End("</h1>");
@@ -149,7 +162,7 @@ StartView::StartView(Gui::Document* pcDocument, QWidget* parent)
setWindowTitle(title);
configureExamplesListWidget(examplesListWidget);
configureRecentFilesListWidget(recentFilesListWidget);
configureRecentFilesListWidget(recentFilesListWidget, recentFilesLabel);
}
@@ -174,6 +187,8 @@ void StartView::configureNewFileButtons(QGridLayout* layout) const
tr("Create an architectural project"),
QLatin1String(":/icons/ArchWorkbench.svg")});
// TODO: Ensure all of the required WBs are actually available
// TODO: Make this layout more flexible (e.g. use a single line if possible)
layout->addWidget(partDesign, 0, 0);
layout->addWidget(assembly, 0, 1);
layout->addWidget(draft, 0, 2);
@@ -200,11 +215,24 @@ void StartView::configureFileCardWidget(QListView* fileCardWidget)
}
void StartView::configureRecentFilesListWidget(QListView* recentFilesListWidget)
void StartView::configureRecentFilesListWidget(QListView* recentFilesListWidget,
QLabel* recentFilesLabel)
{
_recentFilesModel.loadRecentFiles();
recentFilesListWidget->setModel(&_recentFilesModel);
configureFileCardWidget(recentFilesListWidget);
auto recentFilesGroup = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/RecentFiles");
auto numRecentFiles {recentFilesGroup->GetInt("RecentFiles", 0)};
if (numRecentFiles == 0) {
recentFilesListWidget->hide();
recentFilesLabel->hide();
}
else {
recentFilesListWidget->show();
recentFilesLabel->show();
}
}
@@ -311,3 +339,10 @@ void StartView::fileCardSelected(const QModelIndex& index)
Base::Console().Error("An unknown error occurred");
}
}
void StartView::showOnStartupChanged(bool checked)
{
auto hGrp = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Start");
hGrp->SetBool("ShowOnStartup", checked);
}

View File

@@ -33,6 +33,7 @@
#include "../App/ExamplesModel.h"
class QLabel;
class QListView;
class QGridLayout;
class QScrollArea;
@@ -76,13 +77,15 @@ public:
protected:
void configureNewFileButtons(QGridLayout* layout) const;
static void configureFileCardWidget(QListView* fileCardWidget);
void configureRecentFilesListWidget(QListView* recentFilesListWidget);
void configureRecentFilesListWidget(QListView* recentFilesListWidget, QLabel* recentFilesLabel);
void configureExamplesListWidget(QListView* examplesListWidget);
void postStart(PostStartBehavior behavior) const;
void fileCardSelected(const QModelIndex& index);
void showOnStartupChanged(bool checked);
private:
QScrollArea* _contents = nullptr;
Start::RecentFilesModel _recentFilesModel;

View File

@@ -24,5 +24,5 @@
import StartGui # Not unused, import has a side-effect of creating the "Start_Start" command
import StartMigrator
migrator = StartMigrator.StartMigrator2024()
migrator.run_migration()
# migrator = StartMigrator.StartMigrator2024()
# migrator.run_migration()