Welcome: Implement new design
2024 redesign Change-Id: I6629849921272d856f201693973a8e29c6465e94 Reviewed-by: hjk <hjk@qt.io> Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
@@ -1,4 +1,5 @@
|
|||||||
[General]
|
[General]
|
||||||
|
Includes=dark.figmatokens
|
||||||
ThemeName=Dark
|
ThemeName=Dark
|
||||||
PreferredStyles=
|
PreferredStyles=
|
||||||
DefaultTextEditorColorScheme=dark.xml
|
DefaultTextEditorColorScheme=dark.xml
|
||||||
@@ -406,39 +407,6 @@ Debugger_WatchItem_ValueChanged=ffff6666
|
|||||||
|
|
||||||
Debugger_Breakpoint_TextMarkColor=ffff4040
|
Debugger_Breakpoint_TextMarkColor=ffff4040
|
||||||
|
|
||||||
; Qt Creator Color Tokens - dark mode
|
|
||||||
Token_Basic_Black=ff131313
|
|
||||||
Token_Basic_White=fff8f8f8
|
|
||||||
Token_Accent_Default=ff23b26a
|
|
||||||
Token_Accent_Muted=ff1f9b5d
|
|
||||||
Token_Accent_Subtle=ff1a8550
|
|
||||||
Token_Background_Default=ff1f1f1f
|
|
||||||
Token_Background_Muted=ff262626
|
|
||||||
Token_Background_Subtle=ff2e2e2e
|
|
||||||
Token_Foreground_Default=ff5a5a5a
|
|
||||||
Token_Foreground_Muted=ff3e3e3e
|
|
||||||
Token_Foreground_Subtle=ff303030
|
|
||||||
Token_Text_Default=fff8f8f8
|
|
||||||
Token_Text_Muted=ffaeaeae
|
|
||||||
Token_Text_Subtle=ff595959
|
|
||||||
Token_Stroke_Strong=ffeeeeee
|
|
||||||
Token_Stroke_Muted=ff727272
|
|
||||||
Token_Stroke_Subtle=ff3a3a3a
|
|
||||||
Token_Notification_Alert=ffc98014
|
|
||||||
Token_Notification_Success=ff1f9b5d
|
|
||||||
Token_Notification_Neutral=ff016876
|
|
||||||
Token_Notification_Danger=ffb22245
|
|
||||||
|
|
||||||
Welcome_TextColor=text
|
|
||||||
Welcome_ForegroundPrimaryColor=ffa3a3a3
|
|
||||||
Welcome_ForegroundSecondaryColor=ff808080
|
|
||||||
Welcome_BackgroundPrimaryColor=normalBackground
|
|
||||||
Welcome_BackgroundSecondaryColor=shadowBackground
|
|
||||||
Welcome_HoverColor=ff404040
|
|
||||||
Welcome_AccentColor=ff57d658
|
|
||||||
Welcome_LinkColor=ff67e668
|
|
||||||
Welcome_DisabledLinkColor=textDisabled
|
|
||||||
|
|
||||||
Timeline_TextColor=text
|
Timeline_TextColor=text
|
||||||
Timeline_BackgroundColor1=normalBackground
|
Timeline_BackgroundColor1=normalBackground
|
||||||
Timeline_BackgroundColor2=ff444444
|
Timeline_BackgroundColor2=ff444444
|
||||||
|
31
share/qtcreator/themes/dark.figmatokens
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
; Qt Creator Color Tokens - dark mode
|
||||||
|
|
||||||
|
[Colors]
|
||||||
|
|
||||||
|
Token_Basic_Black=ff131313
|
||||||
|
Token_Basic_White=fff8f8f8
|
||||||
|
|
||||||
|
Token_Accent_Default=ff23b26a
|
||||||
|
Token_Accent_Muted=ff1f9b5d
|
||||||
|
Token_Accent_Subtle=ff1a8550
|
||||||
|
|
||||||
|
Token_Background_Default=ff1f1f1f
|
||||||
|
Token_Background_Muted=ff262626
|
||||||
|
Token_Background_Subtle=ff2e2e2e
|
||||||
|
|
||||||
|
Token_Foreground_Default=ff5a5a5a
|
||||||
|
Token_Foreground_Muted=ff3e3e3e
|
||||||
|
Token_Foreground_Subtle=ff303030
|
||||||
|
|
||||||
|
Token_Text_Default=fff8f8f8
|
||||||
|
Token_Text_Muted=ffaeaeae
|
||||||
|
Token_Text_Subtle=ff595959
|
||||||
|
|
||||||
|
Token_Stroke_Strong=ffeeeeee
|
||||||
|
Token_Stroke_Muted=ff727272
|
||||||
|
Token_Stroke_Subtle=ff3a3a3a
|
||||||
|
|
||||||
|
Token_Notification_Alert=ffc98014
|
||||||
|
Token_Notification_Success=ff1f9b5d
|
||||||
|
Token_Notification_Neutral=ff016876
|
||||||
|
Token_Notification_Danger=ffb22245
|
@@ -1,4 +1,5 @@
|
|||||||
[General]
|
[General]
|
||||||
|
Includes=light.figmatokens
|
||||||
ThemeName=Classic
|
ThemeName=Classic
|
||||||
PreferredStyles=
|
PreferredStyles=
|
||||||
|
|
||||||
@@ -398,39 +399,6 @@ Debugger_WatchItem_ValueChanged=ffc80000
|
|||||||
|
|
||||||
Debugger_Breakpoint_TextMarkColor=ffff4040
|
Debugger_Breakpoint_TextMarkColor=ffff4040
|
||||||
|
|
||||||
; Qt Creator Color Tokens - light mode
|
|
||||||
Token_Basic_Black=ff131313
|
|
||||||
Token_Basic_White=fff2f2f2
|
|
||||||
Token_Accent_Default=ff23b26a
|
|
||||||
Token_Accent_Muted=ff1f9b5d
|
|
||||||
Token_Accent_Subtle=ff1a8550
|
|
||||||
Token_Background_Default=ffe3e3e3
|
|
||||||
Token_Background_Muted=ffeeeeee
|
|
||||||
Token_Background_Subtle=fffbfbfb
|
|
||||||
Token_Foreground_Default=ffcdcdcd
|
|
||||||
Token_Foreground_Muted=ffd5d5d5
|
|
||||||
Token_Foreground_Subtle=ffdddddd
|
|
||||||
Token_Text_Default=ff393939
|
|
||||||
Token_Text_Muted=ff7c7c7c
|
|
||||||
Token_Text_Subtle=ffbebebe
|
|
||||||
Token_Stroke_Strong=ff464646
|
|
||||||
Token_Stroke_Muted=ff727272
|
|
||||||
Token_Stroke_Subtle=ffcdcdcd
|
|
||||||
Token_Notification_Alert=ffeb991f
|
|
||||||
Token_Notification_Success=ff23b26a
|
|
||||||
Token_Notification_Neutral=ff0e7887
|
|
||||||
Token_Notification_Danger=ffdc1343
|
|
||||||
|
|
||||||
Welcome_TextColor=ff000000
|
|
||||||
Welcome_ForegroundPrimaryColor=shadowBackground
|
|
||||||
Welcome_ForegroundSecondaryColor=ff939393
|
|
||||||
Welcome_BackgroundPrimaryColor=fffafafa
|
|
||||||
Welcome_BackgroundSecondaryColor=ffffffff
|
|
||||||
Welcome_HoverColor=ffefefef
|
|
||||||
Welcome_AccentColor=ff45ce55
|
|
||||||
Welcome_LinkColor=ff20a020
|
|
||||||
Welcome_DisabledLinkColor=textDisabled
|
|
||||||
|
|
||||||
Timeline_TextColor=darkText
|
Timeline_TextColor=darkText
|
||||||
Timeline_BackgroundColor1=ffffffff
|
Timeline_BackgroundColor1=ffffffff
|
||||||
Timeline_BackgroundColor2=fff6f6f6
|
Timeline_BackgroundColor2=fff6f6f6
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
[General]
|
[General]
|
||||||
|
Includes=light.figmatokens
|
||||||
ThemeName=Design Light
|
ThemeName=Design Light
|
||||||
PreferredStyles=
|
PreferredStyles=
|
||||||
|
|
||||||
@@ -410,39 +411,6 @@ Debugger_WatchItem_ValueChanged=ffbf0303
|
|||||||
|
|
||||||
Debugger_Breakpoint_TextMarkColor=ffff4040
|
Debugger_Breakpoint_TextMarkColor=ffff4040
|
||||||
|
|
||||||
; Qt Creator Color Tokens - light mode
|
|
||||||
Token_Basic_Black=ff131313
|
|
||||||
Token_Basic_White=fff2f2f2
|
|
||||||
Token_Accent_Default=ff23b26a
|
|
||||||
Token_Accent_Muted=ff1f9b5d
|
|
||||||
Token_Accent_Subtle=ff1a8550
|
|
||||||
Token_Background_Default=ffe3e3e3
|
|
||||||
Token_Background_Muted=ffeeeeee
|
|
||||||
Token_Background_Subtle=fffbfbfb
|
|
||||||
Token_Foreground_Default=ffcdcdcd
|
|
||||||
Token_Foreground_Muted=ffd5d5d5
|
|
||||||
Token_Foreground_Subtle=ffdddddd
|
|
||||||
Token_Text_Default=ff393939
|
|
||||||
Token_Text_Muted=ff7c7c7c
|
|
||||||
Token_Text_Subtle=ffbebebe
|
|
||||||
Token_Stroke_Strong=ff464646
|
|
||||||
Token_Stroke_Muted=ff727272
|
|
||||||
Token_Stroke_Subtle=ffcdcdcd
|
|
||||||
Token_Notification_Alert=ffeb991f
|
|
||||||
Token_Notification_Success=ff23b26a
|
|
||||||
Token_Notification_Neutral=ff0e7887
|
|
||||||
Token_Notification_Danger=ffdc1343
|
|
||||||
|
|
||||||
Welcome_TextColor=ff000000
|
|
||||||
Welcome_ForegroundPrimaryColor=ff404040
|
|
||||||
Welcome_ForegroundSecondaryColor=ff727272
|
|
||||||
Welcome_BackgroundPrimaryColor=ffeaeaea
|
|
||||||
Welcome_BackgroundSecondaryColor=ffefefef
|
|
||||||
Welcome_HoverColor=ffe1e1e1
|
|
||||||
Welcome_AccentColor=ff25709a
|
|
||||||
Welcome_LinkColor=ff104090
|
|
||||||
Welcome_DisabledLinkColor=textDisabled
|
|
||||||
|
|
||||||
Timeline_TextColor=text
|
Timeline_TextColor=text
|
||||||
Timeline_BackgroundColor1=normalBackground
|
Timeline_BackgroundColor1=normalBackground
|
||||||
Timeline_BackgroundColor2=fff6f6f6
|
Timeline_BackgroundColor2=fff6f6f6
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
[General]
|
[General]
|
||||||
|
Includes=dark.figmatokens
|
||||||
ThemeName=Design Dark
|
ThemeName=Design Dark
|
||||||
PreferredStyles=
|
PreferredStyles=
|
||||||
DefaultTextEditorColorScheme=creator-dark.xml
|
DefaultTextEditorColorScheme=creator-dark.xml
|
||||||
@@ -414,39 +415,6 @@ Debugger_WatchItem_ValueChanged=ffff6666
|
|||||||
|
|
||||||
Debugger_Breakpoint_TextMarkColor=ffff4040
|
Debugger_Breakpoint_TextMarkColor=ffff4040
|
||||||
|
|
||||||
; Qt Creator Color Tokens - dark mode
|
|
||||||
Token_Basic_Black=ff131313
|
|
||||||
Token_Basic_White=fff8f8f8
|
|
||||||
Token_Accent_Default=ff23b26a
|
|
||||||
Token_Accent_Muted=ff1f9b5d
|
|
||||||
Token_Accent_Subtle=ff1a8550
|
|
||||||
Token_Background_Default=ff1f1f1f
|
|
||||||
Token_Background_Muted=ff262626
|
|
||||||
Token_Background_Subtle=ff2e2e2e
|
|
||||||
Token_Foreground_Default=ff5a5a5a
|
|
||||||
Token_Foreground_Muted=ff3e3e3e
|
|
||||||
Token_Foreground_Subtle=ff303030
|
|
||||||
Token_Text_Default=fff8f8f8
|
|
||||||
Token_Text_Muted=ffaeaeae
|
|
||||||
Token_Text_Subtle=ff595959
|
|
||||||
Token_Stroke_Strong=ffeeeeee
|
|
||||||
Token_Stroke_Muted=ff727272
|
|
||||||
Token_Stroke_Subtle=ff3a3a3a
|
|
||||||
Token_Notification_Alert=ffc98014
|
|
||||||
Token_Notification_Success=ff1f9b5d
|
|
||||||
Token_Notification_Neutral=ff016876
|
|
||||||
Token_Notification_Danger=ffb22245
|
|
||||||
|
|
||||||
Welcome_TextColor=text
|
|
||||||
Welcome_ForegroundPrimaryColor=ffa3a3a3
|
|
||||||
Welcome_ForegroundSecondaryColor=ff808080
|
|
||||||
Welcome_BackgroundPrimaryColor=ff242424
|
|
||||||
Welcome_BackgroundSecondaryColor=ff1c1c1c
|
|
||||||
Welcome_HoverColor=ff2b2a2a
|
|
||||||
Welcome_AccentColor=ff3f8ccc
|
|
||||||
Welcome_LinkColor=ff5fafef
|
|
||||||
Welcome_DisabledLinkColor=textDisabled
|
|
||||||
|
|
||||||
Timeline_TextColor=text
|
Timeline_TextColor=text
|
||||||
Timeline_BackgroundColor1=normalBackground
|
Timeline_BackgroundColor1=normalBackground
|
||||||
Timeline_BackgroundColor2=ff444444
|
Timeline_BackgroundColor2=ff444444
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
[General]
|
[General]
|
||||||
|
Includes=dark.figmatokens
|
||||||
ThemeName=Flat Dark
|
ThemeName=Flat Dark
|
||||||
PreferredStyles=
|
PreferredStyles=
|
||||||
DefaultTextEditorColorScheme=creator-dark.xml
|
DefaultTextEditorColorScheme=creator-dark.xml
|
||||||
@@ -410,39 +411,6 @@ Debugger_WatchItem_ValueChanged=ffff6666
|
|||||||
|
|
||||||
Debugger_Breakpoint_TextMarkColor=ffff4040
|
Debugger_Breakpoint_TextMarkColor=ffff4040
|
||||||
|
|
||||||
; Qt Creator Color Tokens - dark mode
|
|
||||||
Token_Basic_Black=ff131313
|
|
||||||
Token_Basic_White=fff8f8f8
|
|
||||||
Token_Accent_Default=ff23b26a
|
|
||||||
Token_Accent_Muted=ff1f9b5d
|
|
||||||
Token_Accent_Subtle=ff1a8550
|
|
||||||
Token_Background_Default=ff1f1f1f
|
|
||||||
Token_Background_Muted=ff262626
|
|
||||||
Token_Background_Subtle=ff2e2e2e
|
|
||||||
Token_Foreground_Default=ff5a5a5a
|
|
||||||
Token_Foreground_Muted=ff3e3e3e
|
|
||||||
Token_Foreground_Subtle=ff303030
|
|
||||||
Token_Text_Default=fff8f8f8
|
|
||||||
Token_Text_Muted=ffaeaeae
|
|
||||||
Token_Text_Subtle=ff595959
|
|
||||||
Token_Stroke_Strong=ffeeeeee
|
|
||||||
Token_Stroke_Muted=ff727272
|
|
||||||
Token_Stroke_Subtle=ff3a3a3a
|
|
||||||
Token_Notification_Alert=ffc98014
|
|
||||||
Token_Notification_Success=ff1f9b5d
|
|
||||||
Token_Notification_Neutral=ff016876
|
|
||||||
Token_Notification_Danger=ffb22245
|
|
||||||
|
|
||||||
Welcome_TextColor=text
|
|
||||||
Welcome_ForegroundPrimaryColor=ff999999
|
|
||||||
Welcome_ForegroundSecondaryColor=ff808080
|
|
||||||
Welcome_BackgroundPrimaryColor=normalBackground
|
|
||||||
Welcome_BackgroundSecondaryColor=ff242628
|
|
||||||
Welcome_HoverColor=ff404243
|
|
||||||
Welcome_AccentColor=ff36c148
|
|
||||||
Welcome_LinkColor=ff5fcf4f
|
|
||||||
Welcome_DisabledLinkColor=textDisabled
|
|
||||||
|
|
||||||
Timeline_TextColor=text
|
Timeline_TextColor=text
|
||||||
Timeline_BackgroundColor1=normalBackground
|
Timeline_BackgroundColor1=normalBackground
|
||||||
Timeline_BackgroundColor2=ff444444
|
Timeline_BackgroundColor2=ff444444
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
[General]
|
[General]
|
||||||
|
Includes=light.figmatokens
|
||||||
ThemeName=Flat Light
|
ThemeName=Flat Light
|
||||||
PreferredStyles=
|
PreferredStyles=
|
||||||
|
|
||||||
@@ -407,39 +408,6 @@ Debugger_WatchItem_ValueChanged=ffbf0303
|
|||||||
|
|
||||||
Debugger_Breakpoint_TextMarkColor=ffff4040
|
Debugger_Breakpoint_TextMarkColor=ffff4040
|
||||||
|
|
||||||
; Qt Creator Color Tokens - light mode
|
|
||||||
Token_Basic_Black=ff131313
|
|
||||||
Token_Basic_White=fff2f2f2
|
|
||||||
Token_Accent_Default=ff23b26a
|
|
||||||
Token_Accent_Muted=ff1f9b5d
|
|
||||||
Token_Accent_Subtle=ff1a8550
|
|
||||||
Token_Background_Default=ffe3e3e3
|
|
||||||
Token_Background_Muted=ffeeeeee
|
|
||||||
Token_Background_Subtle=fffbfbfb
|
|
||||||
Token_Foreground_Default=ffcdcdcd
|
|
||||||
Token_Foreground_Muted=ffd5d5d5
|
|
||||||
Token_Foreground_Subtle=ffdddddd
|
|
||||||
Token_Text_Default=ff393939
|
|
||||||
Token_Text_Muted=ff7c7c7c
|
|
||||||
Token_Text_Subtle=ffbebebe
|
|
||||||
Token_Stroke_Strong=ff464646
|
|
||||||
Token_Stroke_Muted=ff727272
|
|
||||||
Token_Stroke_Subtle=ffcdcdcd
|
|
||||||
Token_Notification_Alert=ffeb991f
|
|
||||||
Token_Notification_Success=ff23b26a
|
|
||||||
Token_Notification_Neutral=ff0e7887
|
|
||||||
Token_Notification_Danger=ffdc1343
|
|
||||||
|
|
||||||
Welcome_TextColor=ff000000
|
|
||||||
Welcome_ForegroundPrimaryColor=ff232323
|
|
||||||
Welcome_ForegroundSecondaryColor=ff939393
|
|
||||||
Welcome_BackgroundPrimaryColor=fffafafa
|
|
||||||
Welcome_BackgroundSecondaryColor=ffffffff
|
|
||||||
Welcome_HoverColor=ffefefef
|
|
||||||
Welcome_AccentColor=ff45ce55
|
|
||||||
Welcome_LinkColor=ff20a020
|
|
||||||
Welcome_DisabledLinkColor=textDisabled
|
|
||||||
|
|
||||||
Timeline_TextColor=text
|
Timeline_TextColor=text
|
||||||
Timeline_BackgroundColor1=normalBackground
|
Timeline_BackgroundColor1=normalBackground
|
||||||
Timeline_BackgroundColor2=fff6f6f6
|
Timeline_BackgroundColor2=fff6f6f6
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
[General]
|
[General]
|
||||||
|
Includes=light.figmatokens
|
||||||
ThemeName=Flat
|
ThemeName=Flat
|
||||||
PreferredStyles=
|
PreferredStyles=
|
||||||
|
|
||||||
@@ -405,39 +406,6 @@ Debugger_WatchItem_ValueChanged=ffbf0303
|
|||||||
|
|
||||||
Debugger_Breakpoint_TextMarkColor=ffff4040
|
Debugger_Breakpoint_TextMarkColor=ffff4040
|
||||||
|
|
||||||
; Qt Creator Color Tokens - light mode
|
|
||||||
Token_Basic_Black=ff131313
|
|
||||||
Token_Basic_White=fff2f2f2
|
|
||||||
Token_Accent_Default=ff23b26a
|
|
||||||
Token_Accent_Muted=ff1f9b5d
|
|
||||||
Token_Accent_Subtle=ff1a8550
|
|
||||||
Token_Background_Default=ffe3e3e3
|
|
||||||
Token_Background_Muted=ffeeeeee
|
|
||||||
Token_Background_Subtle=fffbfbfb
|
|
||||||
Token_Foreground_Default=ffcdcdcd
|
|
||||||
Token_Foreground_Muted=ffd5d5d5
|
|
||||||
Token_Foreground_Subtle=ffdddddd
|
|
||||||
Token_Text_Default=ff393939
|
|
||||||
Token_Text_Muted=ff7c7c7c
|
|
||||||
Token_Text_Subtle=ffbebebe
|
|
||||||
Token_Stroke_Strong=ff464646
|
|
||||||
Token_Stroke_Muted=ff727272
|
|
||||||
Token_Stroke_Subtle=ffcdcdcd
|
|
||||||
Token_Notification_Alert=ffeb991f
|
|
||||||
Token_Notification_Success=ff23b26a
|
|
||||||
Token_Notification_Neutral=ff0e7887
|
|
||||||
Token_Notification_Danger=ffdc1343
|
|
||||||
|
|
||||||
Welcome_TextColor=ff000000
|
|
||||||
Welcome_ForegroundPrimaryColor=shadowBackground
|
|
||||||
Welcome_ForegroundSecondaryColor=ff939393
|
|
||||||
Welcome_BackgroundPrimaryColor=fffafafa
|
|
||||||
Welcome_BackgroundSecondaryColor=ffffffff
|
|
||||||
Welcome_HoverColor=ffefefef
|
|
||||||
Welcome_AccentColor=ff45ce55
|
|
||||||
Welcome_LinkColor=ff20a020
|
|
||||||
Welcome_DisabledLinkColor=textDisabled
|
|
||||||
|
|
||||||
Timeline_TextColor=text
|
Timeline_TextColor=text
|
||||||
Timeline_BackgroundColor1=normalBackground
|
Timeline_BackgroundColor1=normalBackground
|
||||||
Timeline_BackgroundColor2=fff6f6f6
|
Timeline_BackgroundColor2=fff6f6f6
|
||||||
|
31
share/qtcreator/themes/light.figmatokens
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
; Qt Creator Color Tokens - light mode
|
||||||
|
|
||||||
|
[Colors]
|
||||||
|
|
||||||
|
Token_Basic_Black=ff131313
|
||||||
|
Token_Basic_White=fff2f2f2
|
||||||
|
|
||||||
|
Token_Accent_Default=ff23b26a
|
||||||
|
Token_Accent_Muted=ff1f9b5d
|
||||||
|
Token_Accent_Subtle=ff1a8550
|
||||||
|
|
||||||
|
Token_Background_Default=fffcfcfc
|
||||||
|
Token_Background_Muted=ffefefef
|
||||||
|
Token_Background_Subtle=ffe7e7e7
|
||||||
|
|
||||||
|
Token_Foreground_Default=ffcdcdcd
|
||||||
|
Token_Foreground_Muted=ffd5d5d5
|
||||||
|
Token_Foreground_Subtle=ffdddddd
|
||||||
|
|
||||||
|
Token_Text_Default=ff393939
|
||||||
|
Token_Text_Muted=ff6a6a6a
|
||||||
|
Token_Text_Subtle=ffbebebe
|
||||||
|
|
||||||
|
Token_Stroke_Strong=ff464646
|
||||||
|
Token_Stroke_Muted=ff727272
|
||||||
|
Token_Stroke_Subtle=ffcdcdcd
|
||||||
|
|
||||||
|
Token_Notification_Alert=ffeb991f
|
||||||
|
Token_Notification_Success=ff23b26a
|
||||||
|
Token_Notification_Neutral=ff0e7887
|
||||||
|
Token_Notification_Danger=ffdc1343
|
@@ -933,7 +933,17 @@ QColor StyleHelper::ensureReadableOn(const QColor &background, const QColor &des
|
|||||||
return foreground;
|
return foreground;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QStringList brandFontFamilies()
|
static const QStringList &applicationFontFamilies()
|
||||||
|
{
|
||||||
|
const static QStringList families = [] {
|
||||||
|
constexpr QLatin1String familyName("Inter");
|
||||||
|
// Font is either installed in the system, or was loaded from share/qtcreator/fonts/
|
||||||
|
return QFontDatabase::hasFamily(familyName) ? QStringList(familyName) : QStringList();
|
||||||
|
}();
|
||||||
|
return families;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const QStringList &brandFontFamilies()
|
||||||
{
|
{
|
||||||
const static QStringList families = []{
|
const static QStringList families = []{
|
||||||
const int id = QFontDatabase::addApplicationFont(":/studiofonts/TitilliumWeb-Regular.ttf");
|
const int id = QFontDatabase::addApplicationFont(":/studiofonts/TitilliumWeb-Regular.ttf");
|
||||||
@@ -959,10 +969,14 @@ static const UiFontMetrics& uiFontMetrics(StyleHelper::UiElement element)
|
|||||||
{StyleHelper::UiElementH5, {14, 16, QFont::DemiBold}},
|
{StyleHelper::UiElementH5, {14, 16, QFont::DemiBold}},
|
||||||
{StyleHelper::UiElementH6, {12, 14, QFont::DemiBold}},
|
{StyleHelper::UiElementH6, {12, 14, QFont::DemiBold}},
|
||||||
{StyleHelper::UiElementH6Capital, {12, 14, QFont::DemiBold}},
|
{StyleHelper::UiElementH6Capital, {12, 14, QFont::DemiBold}},
|
||||||
|
{StyleHelper::UiElementBody1, {14, 20, QFont::Light}},
|
||||||
|
{StyleHelper::UiElementBody2, {12, 20, QFont::Light}},
|
||||||
|
{StyleHelper::UiElementButtonMedium, {12, 16, QFont::Bold}},
|
||||||
|
{StyleHelper::UiElementButtonSmall, {10, 12, QFont::Bold}},
|
||||||
{StyleHelper::UiElementCaptionStrong, {10, 12, QFont::DemiBold}},
|
{StyleHelper::UiElementCaptionStrong, {10, 12, QFont::DemiBold}},
|
||||||
{StyleHelper::UiElementCaption, {10, 12, QFont::Normal}},
|
{StyleHelper::UiElementCaption, {10, 12, QFont::Normal}},
|
||||||
{StyleHelper::UIElementIconStandard, {12, 16, QFont::Normal}},
|
{StyleHelper::UiElementIconStandard, {12, 16, QFont::Medium}},
|
||||||
{StyleHelper::UIElementIconActive, {12, 16, QFont::DemiBold}},
|
{StyleHelper::UiElementIconActive, {12, 16, QFont::DemiBold}},
|
||||||
};
|
};
|
||||||
QTC_ASSERT(metrics.count(element) > 0, return metrics.at(StyleHelper::UiElementCaptionStrong));
|
QTC_ASSERT(metrics.count(element) > 0, return metrics.at(StyleHelper::UiElementCaptionStrong));
|
||||||
return metrics.at(element);
|
return metrics.at(element);
|
||||||
@@ -983,8 +997,10 @@ QFont StyleHelper::uiFont(UiElement element)
|
|||||||
case UiElementH3:
|
case UiElementH3:
|
||||||
case UiElementH6Capital:
|
case UiElementH6Capital:
|
||||||
font.setCapitalization(QFont::AllUppercase);
|
font.setCapitalization(QFont::AllUppercase);
|
||||||
break;
|
[[fallthrough]];
|
||||||
default:
|
default:
|
||||||
|
if (!applicationFontFamilies().isEmpty())
|
||||||
|
font.setFamilies(applicationFontFamilies());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -42,15 +42,15 @@ constexpr char C_TOOLBAR_ACTIONWIDGET[] = "toolbar_actionWidget";
|
|||||||
constexpr char C_QT_SCALE_FACTOR_ROUNDING_POLICY[] = "QT_SCALE_FACTOR_ROUNDING_POLICY";
|
constexpr char C_QT_SCALE_FACTOR_ROUNDING_POLICY[] = "QT_SCALE_FACTOR_ROUNDING_POLICY";
|
||||||
|
|
||||||
namespace SpacingTokens {
|
namespace SpacingTokens {
|
||||||
constexpr int VPaddingXXS = 4; // Top and bottom padding within the component
|
constexpr int VPaddingXxs = 4; // Top and bottom padding within the component
|
||||||
constexpr int HPaddingXXS = 4; // Left and right padding within the component
|
constexpr int HPaddingXxs = 4; // Left and right padding within the component
|
||||||
constexpr int VGapXXS = 4; // Vertical Space between TEXT LINE within the Component
|
constexpr int VGapXxs = 4; // Vertical Space between TEXT LINE within the Component
|
||||||
constexpr int HGapXXS = 4; // Horizontal Space between elements within the Component
|
constexpr int HGapXxs = 4; // Horizontal Space between elements within the Component
|
||||||
|
|
||||||
constexpr int VPaddingXS = 8;
|
constexpr int VPaddingXs = 8;
|
||||||
constexpr int HPaddingXS = 8;
|
constexpr int HPaddingXs = 8;
|
||||||
constexpr int VGapXS = 4;
|
constexpr int VGapXs = 4;
|
||||||
constexpr int HGapXS = 8;
|
constexpr int HGapXs = 8;
|
||||||
|
|
||||||
constexpr int VPaddingS = 8;
|
constexpr int VPaddingS = 8;
|
||||||
constexpr int HPaddingS = 16;
|
constexpr int HPaddingS = 16;
|
||||||
@@ -62,10 +62,15 @@ namespace SpacingTokens {
|
|||||||
constexpr int VGapM = 4;
|
constexpr int VGapM = 4;
|
||||||
constexpr int HGapM = 16;
|
constexpr int HGapM = 16;
|
||||||
|
|
||||||
constexpr int VPaddingL = 12;
|
constexpr int VPaddingL = 16;
|
||||||
constexpr int HPaddingL = 24;
|
constexpr int HPaddingL = 24;
|
||||||
constexpr int VGapL = 8;
|
constexpr int VGapL = 8;
|
||||||
constexpr int HGapL = 16;
|
constexpr int HGapL = 16;
|
||||||
|
|
||||||
|
constexpr int ExPaddingGapS = 2;
|
||||||
|
constexpr int ExPaddingGapM = 6;
|
||||||
|
constexpr int ExPaddingGapL = 12;
|
||||||
|
constexpr int ExVPaddingGapXl = 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ToolbarStyle {
|
enum ToolbarStyle {
|
||||||
@@ -82,10 +87,14 @@ enum UiElement {
|
|||||||
UiElementH5,
|
UiElementH5,
|
||||||
UiElementH6,
|
UiElementH6,
|
||||||
UiElementH6Capital,
|
UiElementH6Capital,
|
||||||
|
UiElementBody1,
|
||||||
|
UiElementBody2,
|
||||||
|
UiElementButtonMedium,
|
||||||
|
UiElementButtonSmall,
|
||||||
UiElementCaptionStrong,
|
UiElementCaptionStrong,
|
||||||
UiElementCaption,
|
UiElementCaption,
|
||||||
UIElementIconStandard,
|
UiElementIconStandard,
|
||||||
UIElementIconActive,
|
UiElementIconActive,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Height of the project explorer navigation bar
|
// Height of the project explorer navigation bar
|
||||||
|
@@ -247,18 +247,6 @@ public:
|
|||||||
Token_Notification_Neutral,
|
Token_Notification_Neutral,
|
||||||
Token_Notification_Danger,
|
Token_Notification_Danger,
|
||||||
|
|
||||||
/* Welcome Plugin */
|
|
||||||
|
|
||||||
Welcome_TextColor,
|
|
||||||
Welcome_ForegroundPrimaryColor,
|
|
||||||
Welcome_ForegroundSecondaryColor,
|
|
||||||
Welcome_BackgroundPrimaryColor,
|
|
||||||
Welcome_BackgroundSecondaryColor,
|
|
||||||
Welcome_HoverColor,
|
|
||||||
Welcome_AccentColor,
|
|
||||||
Welcome_LinkColor,
|
|
||||||
Welcome_DisabledLinkColor,
|
|
||||||
|
|
||||||
/* Timeline Library */
|
/* Timeline Library */
|
||||||
Timeline_TextColor,
|
Timeline_TextColor,
|
||||||
Timeline_BackgroundColor1,
|
Timeline_BackgroundColor1,
|
||||||
|
@@ -1,5 +1,9 @@
|
|||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/core">
|
<qresource prefix="/core">
|
||||||
|
<file>images/expandarrow.png</file>
|
||||||
|
<file>images/expandarrow@2x.png</file>
|
||||||
|
<file>images/search.png</file>
|
||||||
|
<file>images/search@2x.png</file>
|
||||||
<file>images/settingscategory_core.png</file>
|
<file>images/settingscategory_core.png</file>
|
||||||
<file>images/settingscategory_core@2x.png</file>
|
<file>images/settingscategory_core@2x.png</file>
|
||||||
<file>images/settingscategory_design.png</file>
|
<file>images/settingscategory_design.png</file>
|
||||||
|
BIN
src/plugins/coreplugin/images/expandarrow.png
Normal file
After Width: | Height: | Size: 169 B |
BIN
src/plugins/coreplugin/images/expandarrow@2x.png
Normal file
After Width: | Height: | Size: 209 B |
BIN
src/plugins/coreplugin/images/search.png
Normal file
After Width: | Height: | Size: 179 B |
BIN
src/plugins/coreplugin/images/search@2x.png
Normal file
After Width: | Height: | Size: 361 B |
@@ -3,25 +3,8 @@
|
|||||||
|
|
||||||
#include "iwelcomepage.h"
|
#include "iwelcomepage.h"
|
||||||
|
|
||||||
#include <utils/icon.h>
|
|
||||||
#include <utils/theme/theme.h>
|
|
||||||
#include <utils/stylehelper.h>
|
|
||||||
|
|
||||||
#include <QHBoxLayout>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QPainter>
|
|
||||||
#include <QPainterPath>
|
|
||||||
#include <QPixmap>
|
|
||||||
#include <QUrl>
|
|
||||||
|
|
||||||
#include <qdrawutil.h>
|
|
||||||
|
|
||||||
using namespace Utils;
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
const char WITHACCENTCOLOR_PROPERTY_NAME[] = "_withAccentColor";
|
|
||||||
|
|
||||||
static QList<IWelcomePage *> g_welcomePages;
|
static QList<IWelcomePage *> g_welcomePages;
|
||||||
|
|
||||||
const QList<IWelcomePage *> IWelcomePage::allWelcomePages()
|
const QList<IWelcomePage *> IWelcomePage::allWelcomePages()
|
||||||
@@ -39,171 +22,4 @@ IWelcomePage::~IWelcomePage()
|
|||||||
g_welcomePages.removeOne(this);
|
g_welcomePages.removeOne(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPalette WelcomePageFrame::buttonPalette(bool isActive, bool isCursorInside, bool forText)
|
|
||||||
{
|
|
||||||
QPalette pal;
|
|
||||||
pal.setBrush(QPalette::Window, {});
|
|
||||||
pal.setBrush(QPalette::WindowText, {});
|
|
||||||
|
|
||||||
Theme *theme = Utils::creatorTheme();
|
|
||||||
if (isActive) {
|
|
||||||
if (forText) {
|
|
||||||
pal.setColor(QPalette::Window, theme->color(Theme::Welcome_ForegroundPrimaryColor));
|
|
||||||
pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_BackgroundPrimaryColor));
|
|
||||||
} else {
|
|
||||||
pal.setColor(QPalette::Window, theme->color(Theme::Welcome_AccentColor));
|
|
||||||
pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_AccentColor));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (isCursorInside) {
|
|
||||||
if (forText) {
|
|
||||||
pal.setColor(QPalette::Window, theme->color(Theme::Welcome_HoverColor));
|
|
||||||
pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_TextColor));
|
|
||||||
} else {
|
|
||||||
pal.setColor(QPalette::Window, theme->color(Theme::Welcome_HoverColor));
|
|
||||||
pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_ForegroundSecondaryColor));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (forText) {
|
|
||||||
pal.setColor(QPalette::Window, theme->color(Theme::Welcome_ForegroundPrimaryColor));
|
|
||||||
pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_TextColor));
|
|
||||||
} else {
|
|
||||||
pal.setColor(QPalette::Window, theme->color(Theme::Welcome_BackgroundPrimaryColor));
|
|
||||||
pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_ForegroundSecondaryColor));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pal;
|
|
||||||
}
|
|
||||||
|
|
||||||
WelcomePageFrame::WelcomePageFrame(QWidget *parent)
|
|
||||||
: QWidget(parent)
|
|
||||||
{
|
|
||||||
setContentsMargins(1, 1, 1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WelcomePageFrame::paintEvent(QPaintEvent *event)
|
|
||||||
{
|
|
||||||
QWidget::paintEvent(event);
|
|
||||||
QPainter p(this);
|
|
||||||
|
|
||||||
qDrawPlainRect(&p, rect(), palette().color(QPalette::WindowText), 1);
|
|
||||||
|
|
||||||
if (property(WITHACCENTCOLOR_PROPERTY_NAME).toBool()) {
|
|
||||||
const int accentRectWidth = 10;
|
|
||||||
const QRect accentRect = rect().adjusted(width() - accentRectWidth, 0, 0, 0);
|
|
||||||
p.fillRect(accentRect, creatorTheme()->color(Theme::Welcome_AccentColor));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class WelcomePageButtonPrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit WelcomePageButtonPrivate(WelcomePageButton *parent)
|
|
||||||
: q(parent) {}
|
|
||||||
bool isActive() const;
|
|
||||||
void doUpdate(bool cursorInside);
|
|
||||||
|
|
||||||
WelcomePageButton *q;
|
|
||||||
QHBoxLayout *m_layout = nullptr;
|
|
||||||
QLabel *m_label = nullptr;
|
|
||||||
|
|
||||||
std::function<void()> onClicked;
|
|
||||||
std::function<bool()> activeChecker;
|
|
||||||
};
|
|
||||||
|
|
||||||
WelcomePageButton::WelcomePageButton(QWidget *parent)
|
|
||||||
: WelcomePageFrame(parent), d(new WelcomePageButtonPrivate(this))
|
|
||||||
{
|
|
||||||
setAutoFillBackground(true);
|
|
||||||
setPalette(buttonPalette(false, false, false));
|
|
||||||
setContentsMargins(0, 1, 0, 1);
|
|
||||||
|
|
||||||
d->m_label = new QLabel(this);
|
|
||||||
d->m_label->setPalette(buttonPalette(false, false, true));
|
|
||||||
d->m_label->setAlignment(Qt::AlignCenter);
|
|
||||||
|
|
||||||
d->m_layout = new QHBoxLayout;
|
|
||||||
d->m_layout->setSpacing(0);
|
|
||||||
d->m_layout->addWidget(d->m_label);
|
|
||||||
setSize(SizeLarge);
|
|
||||||
setLayout(d->m_layout);
|
|
||||||
}
|
|
||||||
|
|
||||||
WelcomePageButton::~WelcomePageButton()
|
|
||||||
{
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WelcomePageButton::mousePressEvent(QMouseEvent *)
|
|
||||||
{
|
|
||||||
if (d->onClicked)
|
|
||||||
d->onClicked();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WelcomePageButton::enterEvent(QEnterEvent *)
|
|
||||||
{
|
|
||||||
d->doUpdate(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WelcomePageButton::leaveEvent(QEvent *)
|
|
||||||
{
|
|
||||||
d->doUpdate(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WelcomePageButtonPrivate::isActive() const
|
|
||||||
{
|
|
||||||
return activeChecker && activeChecker();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WelcomePageButtonPrivate::doUpdate(bool cursorInside)
|
|
||||||
{
|
|
||||||
const bool active = isActive();
|
|
||||||
q->setPalette(WelcomePageFrame::buttonPalette(active, cursorInside, false));
|
|
||||||
const QPalette lpal = WelcomePageFrame::buttonPalette(active, cursorInside, true);
|
|
||||||
m_label->setPalette(lpal);
|
|
||||||
q->update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WelcomePageButton::setText(const QString &text)
|
|
||||||
{
|
|
||||||
d->m_label->setText(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WelcomePageButton::setSize(Size size)
|
|
||||||
{
|
|
||||||
const int hMargin = size == SizeSmall ? 12 : 26;
|
|
||||||
const int vMargin = size == SizeSmall ? 2 : 4;
|
|
||||||
d->m_layout->setContentsMargins(hMargin, vMargin, hMargin, vMargin);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WelcomePageButton::setWithAccentColor(bool withAccent)
|
|
||||||
{
|
|
||||||
setProperty(WITHACCENTCOLOR_PROPERTY_NAME, withAccent);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WelcomePageButton::setActiveChecker(const std::function<bool ()> &value)
|
|
||||||
{
|
|
||||||
d->activeChecker = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WelcomePageButton::recheckActive()
|
|
||||||
{
|
|
||||||
bool isActive = d->isActive();
|
|
||||||
d->doUpdate(isActive);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WelcomePageButton::click()
|
|
||||||
{
|
|
||||||
if (d->onClicked)
|
|
||||||
d->onClicked();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WelcomePageButton::setOnClicked(const std::function<void ()> &value)
|
|
||||||
{
|
|
||||||
d->onClicked = value;
|
|
||||||
if (d->isActive())
|
|
||||||
click();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
@@ -7,13 +7,10 @@
|
|||||||
|
|
||||||
#include <utils/id.h>
|
#include <utils/id.h>
|
||||||
|
|
||||||
#include <QWidget>
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QPixmap;
|
class QWidget;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
@@ -37,43 +34,4 @@ public:
|
|||||||
static const QList<IWelcomePage *> allWelcomePages();
|
static const QList<IWelcomePage *> allWelcomePages();
|
||||||
};
|
};
|
||||||
|
|
||||||
class WelcomePageButtonPrivate;
|
|
||||||
|
|
||||||
class CORE_EXPORT WelcomePageFrame : public QWidget
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
WelcomePageFrame(QWidget *parent);
|
|
||||||
|
|
||||||
void paintEvent(QPaintEvent *event) override;
|
|
||||||
|
|
||||||
static QPalette buttonPalette(bool isActive, bool isCursorInside, bool forText);
|
|
||||||
};
|
|
||||||
|
|
||||||
class CORE_EXPORT WelcomePageButton : public WelcomePageFrame
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum Size {
|
|
||||||
SizeSmall,
|
|
||||||
SizeLarge,
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit WelcomePageButton(QWidget *parent = nullptr);
|
|
||||||
~WelcomePageButton() override;
|
|
||||||
|
|
||||||
void mousePressEvent(QMouseEvent *) override;
|
|
||||||
void enterEvent(QEnterEvent *) override;
|
|
||||||
void leaveEvent(QEvent *) override;
|
|
||||||
|
|
||||||
void setText(const QString &text);
|
|
||||||
void setSize(enum Size);
|
|
||||||
void setWithAccentColor(bool withAccent);
|
|
||||||
void setOnClicked(const std::function<void ()> &value);
|
|
||||||
void setActiveChecker(const std::function<bool ()> &value);
|
|
||||||
void recheckActive();
|
|
||||||
void click();
|
|
||||||
|
|
||||||
private:
|
|
||||||
WelcomePageButtonPrivate *d;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // Core
|
} // Core
|
||||||
|
@@ -267,6 +267,11 @@ QDateTime SessionManager::lastActiveTime(const QString &session)
|
|||||||
return d->m_lastActiveTimes.value(session);
|
return d->m_lastActiveTimes.value(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SessionManager::sessionsCount()
|
||||||
|
{
|
||||||
|
return d->m_sessions.count();
|
||||||
|
}
|
||||||
|
|
||||||
FilePath SessionManager::sessionNameToFileName(const QString &session)
|
FilePath SessionManager::sessionNameToFileName(const QString &session)
|
||||||
{
|
{
|
||||||
return ICore::userResourcePath(session + ".qws");
|
return ICore::userResourcePath(session + ".qws");
|
||||||
|
@@ -34,6 +34,7 @@ public:
|
|||||||
static QStringList sessions();
|
static QStringList sessions();
|
||||||
static QDateTime sessionDateTime(const QString &session);
|
static QDateTime sessionDateTime(const QString &session);
|
||||||
static QDateTime lastActiveTime(const QString &session);
|
static QDateTime lastActiveTime(const QString &session);
|
||||||
|
static int sessionsCount();
|
||||||
|
|
||||||
static bool createSession(const QString &session);
|
static bool createSession(const QString &session);
|
||||||
|
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/fancylineedit.h>
|
#include <utils/fancylineedit.h>
|
||||||
|
#include <utils/icon.h>
|
||||||
#include <utils/layoutbuilder.h>
|
#include <utils/layoutbuilder.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/stylehelper.h>
|
#include <utils/stylehelper.h>
|
||||||
@@ -26,36 +27,34 @@
|
|||||||
|
|
||||||
#include <qdrawutil.h>
|
#include <qdrawutil.h>
|
||||||
|
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0);
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
using namespace WelcomePageHelpers;
|
using namespace WelcomePageHelpers;
|
||||||
|
using namespace StyleHelper::SpacingTokens;
|
||||||
|
|
||||||
static QColor themeColor(Theme::Color role)
|
static QColor themeColor(Theme::Color role)
|
||||||
{
|
{
|
||||||
return creatorTheme()->color(role);
|
return creatorTheme()->color(role);
|
||||||
}
|
}
|
||||||
|
|
||||||
static QFont sizedFont(int size, const QWidget *widget)
|
|
||||||
{
|
|
||||||
QFont f = widget->font();
|
|
||||||
f.setPixelSize(size);
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace WelcomePageHelpers {
|
namespace WelcomePageHelpers {
|
||||||
|
|
||||||
QWidget *panelBar(QWidget *parent)
|
void setBackgroundColor(QWidget *widget, Theme::Color colorRole)
|
||||||
{
|
{
|
||||||
auto frame = new QWidget(parent);
|
QPalette palette = creatorTheme()->palette();
|
||||||
frame->setAutoFillBackground(true);
|
const QPalette::ColorRole role = QPalette::Window;
|
||||||
frame->setMinimumWidth(WelcomePageHelpers::HSpacing);
|
palette.setBrush(role, {});
|
||||||
QPalette pal;
|
palette.setColor(role, creatorTheme()->color(colorRole));
|
||||||
pal.setBrush(QPalette::Window, {});
|
widget->setPalette(palette);
|
||||||
pal.setColor(QPalette::Window, themeColor(Theme::Welcome_BackgroundPrimaryColor));
|
widget->setBackgroundRole(role);
|
||||||
frame->setPalette(pal);
|
widget->setAutoFillBackground(true);
|
||||||
return frame;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawCardBackground(QPainter *painter, const QRectF &rect,
|
void drawCardBackground(QPainter *painter, const QRectF &rect,
|
||||||
@@ -77,30 +76,351 @@ void drawCardBackground(QPainter *painter, const QRectF &rect,
|
|||||||
painter->restore();
|
painter->restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QWidget *createRule(Qt::Orientation orientation, QWidget *parent)
|
||||||
|
{
|
||||||
|
auto rule = new QWidget(parent);
|
||||||
|
if (orientation == Qt::Horizontal)
|
||||||
|
rule->setFixedHeight(1);
|
||||||
|
else
|
||||||
|
rule->setFixedWidth(1);
|
||||||
|
setBackgroundColor(rule, Theme::Token_Stroke_Subtle);
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace WelcomePageHelpers
|
} // namespace WelcomePageHelpers
|
||||||
|
|
||||||
SearchBox::SearchBox(QWidget *parent)
|
enum WidgetState {
|
||||||
: WelcomePageFrame(parent)
|
WidgetStateDefault,
|
||||||
|
WidgetStateChecked,
|
||||||
|
WidgetStateHovered,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const TextFormat &buttonTF(Button::Role role, WidgetState state)
|
||||||
{
|
{
|
||||||
setAutoFillBackground(true);
|
using namespace WelcomePageHelpers;
|
||||||
|
static const TextFormat mediumPrimaryTF
|
||||||
|
{Theme::Token_Basic_White, StyleHelper::UiElement::UiElementButtonMedium,
|
||||||
|
Qt::AlignCenter | Qt::TextDontClip};
|
||||||
|
static const TextFormat mediumSecondaryTF
|
||||||
|
{Theme::Token_Text_Default, mediumPrimaryTF.uiElement, mediumPrimaryTF.drawTextFlags};
|
||||||
|
static const TextFormat smallPrimaryTF
|
||||||
|
{mediumPrimaryTF.themeColor, StyleHelper::UiElement::UiElementButtonSmall,
|
||||||
|
mediumPrimaryTF.drawTextFlags};
|
||||||
|
static const TextFormat smallSecondaryTF
|
||||||
|
{mediumSecondaryTF.themeColor, smallPrimaryTF.uiElement, smallPrimaryTF.drawTextFlags};
|
||||||
|
static const TextFormat smallListDefaultTF
|
||||||
|
{Theme::Token_Text_Default, StyleHelper::UiElement::UiElementIconStandard,
|
||||||
|
Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip};
|
||||||
|
static const TextFormat smallListCheckedTF
|
||||||
|
{smallListDefaultTF.themeColor, StyleHelper::UiElement::UiElementIconActive,
|
||||||
|
smallListDefaultTF.drawTextFlags};
|
||||||
|
static const TextFormat smallLinkDefaultTF
|
||||||
|
{Theme::Token_Text_Default, smallListDefaultTF.uiElement, smallListDefaultTF.drawTextFlags};
|
||||||
|
static const TextFormat smallLinkHoveredTF
|
||||||
|
{Theme::Token_Accent_Default, smallListCheckedTF.uiElement,
|
||||||
|
smallLinkDefaultTF.drawTextFlags};
|
||||||
|
|
||||||
m_lineEdit = new FancyLineEdit;
|
switch (role) {
|
||||||
m_lineEdit->setFiltering(true);
|
case Button::MediumPrimary: return mediumPrimaryTF;
|
||||||
m_lineEdit->setFrame(false);
|
case Button::MediumSecondary: return mediumSecondaryTF;
|
||||||
m_lineEdit->setMinimumHeight(33);
|
case Button::SmallPrimary: return smallPrimaryTF;
|
||||||
m_lineEdit->setAttribute(Qt::WA_MacShowFocusRect, false);
|
case Button::SmallSecondary: return smallSecondaryTF;
|
||||||
|
case Button::SmallList: return (state == WidgetStateDefault) ? smallListDefaultTF
|
||||||
|
: smallListCheckedTF;
|
||||||
|
case Button::SmallLink: return (state == WidgetStateDefault) ? smallLinkDefaultTF
|
||||||
|
: smallLinkHoveredTF;
|
||||||
|
}
|
||||||
|
return mediumPrimaryTF;
|
||||||
|
}
|
||||||
|
|
||||||
QPalette pal = buttonPalette(false, false, true);
|
Button::Button(const QString &text, Role role, QWidget *parent)
|
||||||
// for the margins
|
: QPushButton(text, parent)
|
||||||
pal.setColor(QPalette::Window, m_lineEdit->palette().color(QPalette::Base));
|
, m_role(role)
|
||||||
// for macOS dark mode
|
{
|
||||||
pal.setColor(QPalette::WindowText, themeColor(Theme::Welcome_ForegroundPrimaryColor));
|
// Prevent QMacStyle::subElementRect(SE_PushButtonLayoutItem) from changing our geometry
|
||||||
pal.setColor(QPalette::Text, themeColor(Theme::Welcome_TextColor));
|
setFlat(true);
|
||||||
|
|
||||||
|
updateMargins();
|
||||||
|
if (m_role == SmallList)
|
||||||
|
setCheckable(true);
|
||||||
|
else if (m_role == SmallLink)
|
||||||
|
setCursor(Qt::PointingHandCursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize Button::minimumSizeHint() const
|
||||||
|
{
|
||||||
|
const TextFormat &tf = buttonTF(m_role, WidgetStateHovered);
|
||||||
|
const QFontMetrics fm(tf.font());
|
||||||
|
const QSize textS = fm.size(Qt::TextShowMnemonic, text());
|
||||||
|
const QMargins margins = contentsMargins();
|
||||||
|
return {margins.left() + textS.width() + margins.right(),
|
||||||
|
margins.top() + tf.lineHeight() + margins.bottom()};
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::paintEvent(QPaintEvent *event)
|
||||||
|
{
|
||||||
|
// Without pixmap
|
||||||
|
// +----------------+----------------+----------------+
|
||||||
|
// | |(VPadding[S|XS])| |
|
||||||
|
// | +----------------+----------------+
|
||||||
|
// |(HPadding[S|XS])| <label> |(HPadding[S|XS])|
|
||||||
|
// | +----------------+----------------+
|
||||||
|
// | |(VPadding[S|XS])| |
|
||||||
|
// +----------------+---------------------------------+
|
||||||
|
//
|
||||||
|
// With pixmap
|
||||||
|
// +--------+------------+---------------------------------+
|
||||||
|
// | | |(VPadding[S|XS])| |
|
||||||
|
// | | +----------------+ |
|
||||||
|
// |<pixmap>|(HGap[S|XS])| <label> |(HPadding[S|XS])|
|
||||||
|
// | | +----------------+ |
|
||||||
|
// | | |(VPadding[S|XS])| |
|
||||||
|
// +--------+------------+----------------+----------------+
|
||||||
|
|
||||||
|
using namespace WelcomePageHelpers;
|
||||||
|
const bool hovered = underMouse();
|
||||||
|
const WidgetState state = isChecked() ? WidgetStateChecked : hovered ? WidgetStateHovered
|
||||||
|
: WidgetStateDefault;
|
||||||
|
const TextFormat &tf = buttonTF(m_role, state);
|
||||||
|
const QMargins margins = contentsMargins();
|
||||||
|
const QRect bgR = rect();
|
||||||
|
|
||||||
|
QPainter p(this);
|
||||||
|
|
||||||
|
const qreal brRectRounding = 3.75;
|
||||||
|
switch (m_role) {
|
||||||
|
case MediumPrimary:
|
||||||
|
case SmallPrimary: {
|
||||||
|
const QBrush fill(creatorTheme()->color(isDown()
|
||||||
|
? Theme::Token_Accent_Subtle
|
||||||
|
: hovered ? Theme::Token_Accent_Muted
|
||||||
|
: Theme::Token_Accent_Default));
|
||||||
|
drawCardBackground(&p, bgR, fill, QPen(Qt::NoPen), brRectRounding);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MediumSecondary:
|
||||||
|
case SmallSecondary: {
|
||||||
|
const QPen outline(creatorTheme()->color(Theme::Token_Text_Default), hovered ? 2 : 1);
|
||||||
|
drawCardBackground(&p, bgR, QBrush(Qt::NoBrush), outline, brRectRounding);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SmallList: {
|
||||||
|
if (isChecked() || hovered) {
|
||||||
|
const QBrush fill(creatorTheme()->color(isChecked() ? Theme::Token_Foreground_Muted
|
||||||
|
: Theme::Token_Foreground_Subtle));
|
||||||
|
drawCardBackground(&p, bgR, fill, QPen(Qt::NoPen), brRectRounding);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SmallLink:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_pixmap.isNull()) {
|
||||||
|
const int pixmapHeight = int(m_pixmap.deviceIndependentSize().height());
|
||||||
|
const int pixmapY = (bgR.height() - pixmapHeight) / 2;
|
||||||
|
p.drawPixmap(0, pixmapY, m_pixmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int availableLabelWidth = event->rect().width() - margins.left() - margins.right();
|
||||||
|
const QFont font = tf.font();
|
||||||
|
const QFontMetrics fm(font);
|
||||||
|
const QString elidedLabelText = fm.elidedText(text(), Qt::ElideRight, availableLabelWidth);
|
||||||
|
const QRect labelR(margins.left(), margins.top(), availableLabelWidth, tf.lineHeight());
|
||||||
|
p.setFont(font);
|
||||||
|
p.setPen(tf.color());
|
||||||
|
p.drawText(labelR, tf.drawTextFlags, elidedLabelText);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::setPixmap(const QPixmap &pixmap)
|
||||||
|
{
|
||||||
|
m_pixmap = pixmap;
|
||||||
|
updateMargins();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::updateMargins()
|
||||||
|
{
|
||||||
|
const bool tokenSizeS = m_role == MediumPrimary || m_role == MediumSecondary
|
||||||
|
|| m_role == SmallList || m_role == SmallLink;
|
||||||
|
const int gap = tokenSizeS ? HGapS : HGapXs;
|
||||||
|
const int hPaddingR = tokenSizeS ? HPaddingS : HPaddingXs;
|
||||||
|
const int hPaddingL = m_pixmap.isNull() ? hPaddingR
|
||||||
|
: int(m_pixmap.deviceIndependentSize().width()) + gap;
|
||||||
|
const int vPadding = tokenSizeS ? VPaddingS : VPaddingXs;
|
||||||
|
setContentsMargins(hPaddingL, vPadding, hPaddingR, vPadding);
|
||||||
|
}
|
||||||
|
|
||||||
|
Label::Label(const QString &text, Role role, QWidget *parent)
|
||||||
|
: QLabel(text, parent)
|
||||||
|
, m_role(role)
|
||||||
|
{
|
||||||
|
using namespace WelcomePageHelpers;
|
||||||
|
static const TextFormat primaryTF
|
||||||
|
{Theme::Token_Text_Muted, StyleHelper::UiElement::UiElementH3};
|
||||||
|
static const TextFormat secondaryTF
|
||||||
|
{primaryTF.themeColor, StyleHelper::UiElement::UiElementH6Capital};
|
||||||
|
|
||||||
|
const TextFormat &tF = m_role == Primary ? primaryTF : secondaryTF;
|
||||||
|
const int vPadding = m_role == Primary ? ExPaddingGapM : VPaddingS;
|
||||||
|
|
||||||
|
setFixedHeight(vPadding + tF.lineHeight() + vPadding);
|
||||||
|
setFont(tF.font());
|
||||||
|
QPalette pal = palette();
|
||||||
|
pal.setColor(QPalette::WindowText, tF.color());
|
||||||
|
setPalette(pal);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr TextFormat searchBoxTextTF
|
||||||
|
{Theme::Token_Text_Default, StyleHelper::UiElement::UiElementBody2};
|
||||||
|
constexpr TextFormat searchBoxPlaceholderTF
|
||||||
|
{Theme::Token_Text_Muted, searchBoxTextTF.uiElement};
|
||||||
|
|
||||||
|
static const QPixmap &searchBoxIcon()
|
||||||
|
{
|
||||||
|
static const QPixmap icon = Icon({{FilePath::fromString(":/core/images/search"),
|
||||||
|
Theme::Token_Text_Muted}}, Icon::Tint).pixmap();
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchBox::SearchBox(QWidget *parent)
|
||||||
|
: QLineEdit(parent)
|
||||||
|
{
|
||||||
|
setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||||
|
setAutoFillBackground(false);
|
||||||
|
setFont(searchBoxTextTF.font());
|
||||||
|
setFrame(false);
|
||||||
|
setMouseTracking(true);
|
||||||
|
|
||||||
|
QPalette pal = palette();
|
||||||
|
pal.setColor(QPalette::Base, Qt::transparent);
|
||||||
|
pal.setColor(QPalette::PlaceholderText, searchBoxPlaceholderTF.color());
|
||||||
|
pal.setColor(QPalette::Text, searchBoxTextTF.color());
|
||||||
setPalette(pal);
|
setPalette(pal);
|
||||||
|
|
||||||
auto box = new QHBoxLayout(this);
|
const QSize iconSize = searchBoxIcon().deviceIndependentSize().toSize();
|
||||||
box->setContentsMargins(10, 0, 1, 0);
|
setContentsMargins({HPaddingXs, ExPaddingGapM,
|
||||||
box->addWidget(m_lineEdit);
|
HPaddingXs + iconSize.width() + HPaddingXs, ExPaddingGapM});
|
||||||
|
setFixedHeight(ExPaddingGapM + searchBoxTextTF.lineHeight() + ExPaddingGapM);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize SearchBox::minimumSizeHint() const
|
||||||
|
{
|
||||||
|
const QFontMetrics fm(searchBoxTextTF.font());
|
||||||
|
const QSize textS = fm.size(Qt::TextSingleLine, text());
|
||||||
|
const QMargins margins = contentsMargins();
|
||||||
|
return {margins.left() + textS.width() + margins.right(),
|
||||||
|
margins.top() + searchBoxTextTF.lineHeight() + margins.bottom()};
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchBox::enterEvent(QEnterEvent *event)
|
||||||
|
{
|
||||||
|
QLineEdit::enterEvent(event);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchBox::leaveEvent(QEvent *event)
|
||||||
|
{
|
||||||
|
QLineEdit::leaveEvent(event);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void paintCommonBackground(QPainter *p, const QRectF &rect, const QWidget *widget)
|
||||||
|
{
|
||||||
|
const QBrush fill(creatorTheme()->color(Theme::Token_Background_Muted));
|
||||||
|
const Theme::Color c = widget->hasFocus() ? Theme::Token_Stroke_Strong :
|
||||||
|
widget->underMouse() ? Theme::Token_Stroke_Muted
|
||||||
|
: Theme::Token_Stroke_Subtle;
|
||||||
|
const QPen pen(creatorTheme()->color(c));
|
||||||
|
drawCardBackground(p, rect, fill, pen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchBox::paintEvent(QPaintEvent *event)
|
||||||
|
{
|
||||||
|
// +------------+---------------+------------+------+------------+
|
||||||
|
// | |(ExPaddingGapM)| | | |
|
||||||
|
// | +---------------+ | | |
|
||||||
|
// |(HPaddingXs)| <lineEdit> |(HPaddingXs)|<icon>|(HPaddingXs)|
|
||||||
|
// | +---------------+ | | |
|
||||||
|
// | |(ExPaddingGapM)| | | |
|
||||||
|
// +------------+---------------+------------+------+------------+
|
||||||
|
|
||||||
|
QPainter p(this);
|
||||||
|
|
||||||
|
paintCommonBackground(&p, rect(), this);
|
||||||
|
const QPixmap icon = searchBoxIcon();
|
||||||
|
const QSize iconS = icon.deviceIndependentSize().toSize();
|
||||||
|
const QPoint iconPos(width() - HPaddingXs - iconS.width(), (height() - iconS.height()) / 2);
|
||||||
|
p.drawPixmap(iconPos, icon);
|
||||||
|
|
||||||
|
QLineEdit::paintEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr TextFormat ComboBoxTf
|
||||||
|
{Theme::Token_Text_Muted, StyleHelper::UiElementIconActive,
|
||||||
|
Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip};
|
||||||
|
|
||||||
|
static const QPixmap &comboBoxIcon()
|
||||||
|
{
|
||||||
|
static const QPixmap icon = Icon({{FilePath::fromString(":/core/images/expandarrow"),
|
||||||
|
ComboBoxTf.themeColor}}, Icon::Tint).pixmap();
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComboBox::ComboBox(QWidget *parent)
|
||||||
|
: QComboBox(parent)
|
||||||
|
{
|
||||||
|
setFont(ComboBoxTf.font());
|
||||||
|
setMouseTracking(true);
|
||||||
|
|
||||||
|
const QSize iconSize = comboBoxIcon().deviceIndependentSize().toSize();
|
||||||
|
setContentsMargins({HPaddingXs, VPaddingXs,
|
||||||
|
HGapXxs + iconSize.width() + HPaddingXs, VPaddingXs});
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize ComboBox::sizeHint() const
|
||||||
|
{
|
||||||
|
const QSize parentS = QComboBox::sizeHint();
|
||||||
|
const QMargins margins = contentsMargins();
|
||||||
|
return {margins.left() + parentS.width() + margins.right(),
|
||||||
|
margins.top() + ComboBoxTf.lineHeight() + margins.bottom()};
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComboBox::enterEvent(QEnterEvent *event)
|
||||||
|
{
|
||||||
|
QComboBox::enterEvent(event);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComboBox::leaveEvent(QEvent *event)
|
||||||
|
{
|
||||||
|
QComboBox::leaveEvent(event);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComboBox::paintEvent(QPaintEvent *)
|
||||||
|
{
|
||||||
|
// +------------+-------------+---------+-------+------------+
|
||||||
|
// | | (VPaddingXs)| | | |
|
||||||
|
// | +-------------+ | | |
|
||||||
|
// |(HPaddingXs)|<currentItem>|(HGapXxs)|<arrow>|(HPaddingXs)|
|
||||||
|
// | +-------------+ | | |
|
||||||
|
// | | (VPaddingXs)| | | |
|
||||||
|
// +------------+-------------+---------+-------+------------+
|
||||||
|
|
||||||
|
QPainter p(this);
|
||||||
|
paintCommonBackground(&p, rect(), this);
|
||||||
|
|
||||||
|
const QMargins margins = contentsMargins();
|
||||||
|
const QRect textR(margins.left(), margins.top(),
|
||||||
|
width() - margins.right(), ComboBoxTf.lineHeight());
|
||||||
|
p.setFont(ComboBoxTf.font());
|
||||||
|
p.setPen(ComboBoxTf.color());
|
||||||
|
p.drawText(textR, ComboBoxTf.drawTextFlags, currentText());
|
||||||
|
|
||||||
|
const QPixmap icon = comboBoxIcon();
|
||||||
|
const QSize iconS = icon.deviceIndependentSize().toSize();
|
||||||
|
const QPoint iconPos(width() - HPaddingXs - iconS.width(), (height() - iconS.height()) / 2);
|
||||||
|
p.drawPixmap(iconPos, icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
GridView::GridView(QWidget *parent)
|
GridView::GridView(QWidget *parent)
|
||||||
@@ -115,7 +435,7 @@ GridView::GridView(QWidget *parent)
|
|||||||
setUniformItemSizes(true);
|
setUniformItemSizes(true);
|
||||||
|
|
||||||
QPalette pal;
|
QPalette pal;
|
||||||
pal.setColor(QPalette::Base, themeColor(Theme::Welcome_BackgroundSecondaryColor));
|
pal.setColor(QPalette::Base, themeColor(Theme::Token_Background_Default));
|
||||||
setPalette(pal); // Makes a difference on Mac.
|
setPalette(pal); // Makes a difference on Mac.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,10 +467,11 @@ bool SectionGridView::hasHeightForWidth() const
|
|||||||
|
|
||||||
int SectionGridView::heightForWidth(int width) const
|
int SectionGridView::heightForWidth(int width) const
|
||||||
{
|
{
|
||||||
const int columnCount = qMax(1, width / Core::WelcomePageHelpers::GridItemWidth);
|
const QSize itemSize = ListItemDelegate::itemSize();
|
||||||
|
const int columnCount = qMax(1, width / itemSize.width());
|
||||||
const int rowCount = (model()->rowCount() + columnCount - 1) / columnCount;
|
const int rowCount = (model()->rowCount() + columnCount - 1) / columnCount;
|
||||||
const int maxRowCount = m_maxRows ? std::min(*m_maxRows, rowCount) : rowCount;
|
const int maxRowCount = m_maxRows ? std::min(*m_maxRows, rowCount) : rowCount;
|
||||||
return maxRowCount * Core::WelcomePageHelpers::GridItemHeight;
|
return maxRowCount * itemSize.height();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SectionGridView::wheelEvent(QWheelEvent *e)
|
void SectionGridView::wheelEvent(QWheelEvent *e)
|
||||||
@@ -165,8 +486,9 @@ bool SectionGridView::event(QEvent *e)
|
|||||||
{
|
{
|
||||||
if (e->type() == QEvent::Resize) {
|
if (e->type() == QEvent::Resize) {
|
||||||
const auto itemsFit = [this](const QSize &size) {
|
const auto itemsFit = [this](const QSize &size) {
|
||||||
const int maxColumns = std::max(size.width() / WelcomePageHelpers::GridItemWidth, 1);
|
const QSize itemSize = ListItemDelegate::itemSize();
|
||||||
const int maxRows = std::max(size.height() / WelcomePageHelpers::GridItemHeight, 1);
|
const int maxColumns = std::max(size.width() / itemSize.width(), 1);
|
||||||
|
const int maxRows = std::max(size.height() / itemSize.height(), 1);
|
||||||
const int maxItems = maxColumns * maxRows;
|
const int maxItems = maxColumns * maxRows;
|
||||||
const int items = model()->rowCount();
|
const int items = model()->rowCount();
|
||||||
return maxItems >= items;
|
return maxItems >= items;
|
||||||
@@ -426,47 +748,123 @@ bool ListModelFilter::leaveFilterAcceptsRowBeforeFiltering(const ListItem *, boo
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ListItemDelegate::ListItemDelegate()
|
constexpr TextFormat titleTF {Theme::Token_Text_Default, StyleHelper::UiElementIconActive};
|
||||||
: backgroundPrimaryColor(themeColor(Theme::Welcome_BackgroundPrimaryColor))
|
constexpr TextFormat descriptionTF {titleTF.themeColor, StyleHelper::UiElementCaption};
|
||||||
, backgroundSecondaryColor(themeColor(Theme::Welcome_BackgroundSecondaryColor))
|
constexpr TextFormat tagsLabelTF {Theme::Token_Text_Muted, StyleHelper::UiElementCaptionStrong};
|
||||||
, foregroundPrimaryColor(themeColor(Theme::Welcome_ForegroundPrimaryColor))
|
constexpr TextFormat tagsTF {Theme::Token_Accent_Default, tagsLabelTF.uiElement};
|
||||||
, foregroundSecondaryColor(themeColor(Theme::Welcome_ForegroundSecondaryColor))
|
|
||||||
, hoverColor(themeColor(Theme::Welcome_HoverColor))
|
constexpr qreal itemOutlineWidth = 1;
|
||||||
, textColor(themeColor(Theme::Welcome_TextColor))
|
constexpr qreal itemCornerRounding = 6;
|
||||||
|
constexpr int thumbnailAreaBorderWidth = 1;
|
||||||
|
constexpr QSize thumbnailAreaSize =
|
||||||
|
WelcomeThumbnailSize.grownBy({thumbnailAreaBorderWidth, thumbnailAreaBorderWidth,
|
||||||
|
thumbnailAreaBorderWidth, thumbnailAreaBorderWidth});
|
||||||
|
constexpr int tagsRowsCount = 1;
|
||||||
|
constexpr int tagsHGap = ExPaddingGapM;
|
||||||
|
|
||||||
|
constexpr QEasingCurve::Type hoverEasing = QEasingCurve::OutCubic;
|
||||||
|
constexpr std::chrono::milliseconds hoverDuration(300);
|
||||||
|
constexpr int hoverBlurRadius = 50;
|
||||||
|
constexpr qreal hoverBlurOpacity = 0.175;
|
||||||
|
|
||||||
|
QSize ListItemDelegate::itemSize()
|
||||||
{
|
{
|
||||||
|
const int tagsTfLineHeight = tagsTF.lineHeight();
|
||||||
|
const int width =
|
||||||
|
ExPaddingGapL
|
||||||
|
+ thumbnailAreaSize.width()
|
||||||
|
+ ExPaddingGapL;
|
||||||
|
const int height =
|
||||||
|
ExPaddingGapL
|
||||||
|
+ thumbnailAreaSize.height()
|
||||||
|
+ VGapL
|
||||||
|
+ titleTF.lineHeight()
|
||||||
|
+ VGapL
|
||||||
|
+ tagsTfLineHeight
|
||||||
|
+ (tagsTfLineHeight + ExPaddingGapS) * (tagsRowsCount - 1) // If more than one row
|
||||||
|
+ ExPaddingGapL;
|
||||||
|
return {width + ExVPaddingGapXl, height + ExVPaddingGapXl};
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
void ListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||||
const QModelIndex &index) const
|
const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
|
// Unhovered tile
|
||||||
|
// +---------------+------------------+---------------+-----------------+
|
||||||
|
// | | (ExPaddingGapL) | | |
|
||||||
|
// | +------------------+ | |
|
||||||
|
// | | <thumbnail> | | |
|
||||||
|
// | +------------------+ | |
|
||||||
|
// | | (VGapL) | | |
|
||||||
|
// | +------------------+ | |
|
||||||
|
// |(ExPaddingGapL)| <title> |(ExPaddingGapL)|(ExVPaddingGapXs)|
|
||||||
|
// | +------------------+ | |
|
||||||
|
// | | (VGapL) | | |
|
||||||
|
// | +-----------+------+ | |
|
||||||
|
// | |<tagsLabel>|<tags>| | |
|
||||||
|
// | +-----------+------+ | |
|
||||||
|
// | | (ExPaddingGapL) | | |
|
||||||
|
// +---------------+------------------+---------------+-----------------+
|
||||||
|
// | (ExVPaddingGapXs) |
|
||||||
|
// +--------------------------------------------------------------------+
|
||||||
|
//
|
||||||
|
// Hovered, final animation state of the are above tagsLabel
|
||||||
|
// +---------------+------------------+---------------+
|
||||||
|
// | | (ExPaddingGapL) | |
|
||||||
|
// | +------------------+ |
|
||||||
|
// | | <title> | |
|
||||||
|
// | +------------------+ |
|
||||||
|
// | | (ExPaddingGapS) | |
|
||||||
|
// |(ExPaddingGapL)+------------------+(ExPaddingGapL)| ...
|
||||||
|
// | | <hr> | |
|
||||||
|
// | +------------------+ |
|
||||||
|
// | | (ExPaddingGapS) | |
|
||||||
|
// | +------------------+ |
|
||||||
|
// | | <description> | |
|
||||||
|
// +---------------+------------------+---------------+
|
||||||
|
// ...
|
||||||
|
|
||||||
const ListItem *item = index.data(ListModel::ItemRole).value<Core::ListItem *>();
|
const ListItem *item = index.data(ListModel::ItemRole).value<Core::ListItem *>();
|
||||||
|
|
||||||
const QRect rc = option.rect;
|
const QFont tagsLabelFont = tagsLabelTF.font();
|
||||||
const QRect tileRect(0, 0, rc.width() - GridItemGap, rc.height() - GridItemGap);
|
const QFontMetrics tagsLabelFM(tagsLabelFont);
|
||||||
const QSize thumbnailBgSize = GridItemImageSize.grownBy(QMargins(1, 1, 1, 1));
|
const QFont descriptionFont = descriptionTF.font();
|
||||||
const QRect thumbnailBgRect((tileRect.width() - thumbnailBgSize.width()) / 2, GridItemGap,
|
const QFontMetrics descriptionFM(descriptionFont);
|
||||||
thumbnailBgSize.width(), thumbnailBgSize.height());
|
|
||||||
const QRect textArea = tileRect.adjusted(GridItemGap, GridItemGap, -GridItemGap, -GridItemGap);
|
const QRect bgRGlobal = option.rect.adjusted(0, 0, -ExVPaddingGapXl, -ExVPaddingGapXl);
|
||||||
|
const QRect bgR = bgRGlobal.translated(-option.rect.topLeft());
|
||||||
|
const QRect thumbnailAreaR(bgR.left() + ExPaddingGapL, bgR.top() + ExPaddingGapL,
|
||||||
|
thumbnailAreaSize.width(), thumbnailAreaSize.height());
|
||||||
|
const QRect titleR(thumbnailAreaR.left(), thumbnailAreaR.bottom() + VGapL + 1,
|
||||||
|
thumbnailAreaR.width(), titleTF.lineHeight());
|
||||||
|
const QString tagsLabelText = Tr::tr("Tags:");
|
||||||
|
const int tagsLabelTextWidth = tagsLabelFM.horizontalAdvance(tagsLabelText);
|
||||||
|
const QRect tagsLabelR(titleR.left(), titleR.bottom() + VGapL + 1,
|
||||||
|
tagsLabelTextWidth, tagsTF.lineHeight());
|
||||||
|
const QRect tagsR(tagsLabelR.right() + 1 + tagsHGap, tagsLabelR.top(),
|
||||||
|
bgR.right() - ExPaddingGapL - tagsLabelR.right() - tagsHGap,
|
||||||
|
tagsLabelR.height()
|
||||||
|
+ (tagsLabelR.height() + ExPaddingGapS) * (tagsRowsCount - 1));
|
||||||
|
QTC_CHECK(option.rect.height() == tagsR.bottom() + 1 + ExPaddingGapL + ExVPaddingGapXl);
|
||||||
|
QTC_CHECK(option.rect.width() == tagsR.right() + 1 + ExPaddingGapL + ExVPaddingGapXl);
|
||||||
|
|
||||||
|
QTextOption wrapTO;
|
||||||
|
wrapTO.setWrapMode(QTextOption::WordWrap);
|
||||||
|
|
||||||
const bool hovered = option.state & QStyle::State_MouseOver;
|
const bool hovered = option.state & QStyle::State_MouseOver;
|
||||||
|
|
||||||
constexpr int TagsSeparatorY = GridItemHeight - GridItemGap - 52;
|
|
||||||
constexpr int tagsBase = TagsSeparatorY + 17;
|
|
||||||
constexpr int shiftY = TagsSeparatorY - 16;
|
|
||||||
constexpr int nameY = TagsSeparatorY - 20;
|
|
||||||
|
|
||||||
const QRect textRect = textArea.translated(0, nameY);
|
|
||||||
const QFont descriptionFont = sizedFont(11, option.widget);
|
|
||||||
|
|
||||||
painter->save();
|
painter->save();
|
||||||
painter->translate(rc.topLeft());
|
painter->translate(bgRGlobal.topLeft());
|
||||||
|
|
||||||
painter->fillRect(tileRect, hovered ? hoverColor : backgroundPrimaryColor);
|
const QColor fill(themeColor(hovered ? Theme::Token_Foreground_Muted
|
||||||
|
: Theme::Token_Background_Muted));
|
||||||
|
const QPen pen(themeColor(hovered ? Theme::Token_Foreground_Muted
|
||||||
|
: Theme::Token_Stroke_Subtle), itemOutlineWidth);
|
||||||
|
WelcomePageHelpers::drawCardBackground(painter, bgR, fill, pen, itemCornerRounding);
|
||||||
|
|
||||||
QTextOption wrapped;
|
const int shiftY = thumbnailAreaR.bottom();
|
||||||
wrapped.setWrapMode(QTextOption::WordWrap);
|
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
float animationProgress = 0; // Linear increase from 0.0 to 1.0 during hover animation
|
qreal animationProgress = 0; // Linear increase from 0.0 to 1.0 during hover animation
|
||||||
if (hovered) {
|
if (hovered) {
|
||||||
if (index != m_previousIndex) {
|
if (index != m_previousIndex) {
|
||||||
m_previousIndex = index;
|
m_previousIndex = index;
|
||||||
@@ -476,12 +874,12 @@ void ListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti
|
|||||||
m_currentWidget = qobject_cast<QAbstractItemView *>(
|
m_currentWidget = qobject_cast<QAbstractItemView *>(
|
||||||
const_cast<QWidget *>(option.widget));
|
const_cast<QWidget *>(option.widget));
|
||||||
}
|
}
|
||||||
constexpr float hoverAnimationDuration = 260;
|
animationProgress = qreal(m_startTime.elapsed()) / hoverDuration.count();
|
||||||
animationProgress = m_startTime.elapsed() / hoverAnimationDuration;
|
|
||||||
if (animationProgress < 1) {
|
if (animationProgress < 1) {
|
||||||
static const QEasingCurve animationCurve(QEasingCurve::OutCubic);
|
static const QEasingCurve animationCurve(hoverEasing);
|
||||||
offset = animationCurve.valueForProgress(animationProgress) * shiftY;
|
offset = animationCurve.valueForProgress(animationProgress) * shiftY;
|
||||||
QTimer::singleShot(10, this, &ListItemDelegate::goon);
|
using namespace std::chrono_literals;
|
||||||
|
QTimer::singleShot(10ms, this, &ListItemDelegate::goon);
|
||||||
} else {
|
} else {
|
||||||
offset = shiftY;
|
offset = shiftY;
|
||||||
}
|
}
|
||||||
@@ -489,124 +887,125 @@ void ListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti
|
|||||||
m_previousIndex = QModelIndex();
|
m_previousIndex = QModelIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
const QRect shiftedTextRect = textRect.adjusted(0, -offset, 0, -offset);
|
|
||||||
|
|
||||||
// The pixmap.
|
// The pixmap.
|
||||||
const QPixmap pm = index.data(ListModel::ItemImageRole).value<QPixmap>();
|
const QPixmap pm = index.data(ListModel::ItemImageRole).value<QPixmap>();
|
||||||
QPoint thumbnailPos = thumbnailBgRect.center();
|
QPoint thumbnailPos = thumbnailAreaR.center();
|
||||||
if (!pm.isNull()) {
|
if (!pm.isNull()) {
|
||||||
painter->fillRect(thumbnailBgRect, backgroundSecondaryColor);
|
painter->fillRect(thumbnailAreaR, themeColor(Theme::Token_Background_Default));
|
||||||
|
|
||||||
thumbnailPos.rx() -= pm.width() / pm.devicePixelRatio() / 2 - 1;
|
thumbnailPos.rx() -= pm.width() / pm.devicePixelRatio() / 2 - 1;
|
||||||
thumbnailPos.ry() -= pm.height() / pm.devicePixelRatio() / 2 - 1;
|
thumbnailPos.ry() -= pm.height() / pm.devicePixelRatio() / 2 - 1;
|
||||||
painter->drawPixmap(thumbnailPos, pm);
|
painter->drawPixmap(thumbnailPos, pm);
|
||||||
|
|
||||||
painter->setPen(foregroundPrimaryColor);
|
painter->setPen(titleTF.color());
|
||||||
drawPixmapOverlay(item, painter, option, thumbnailBgRect);
|
drawPixmapOverlay(item, painter, option, thumbnailAreaR);
|
||||||
} else {
|
} else {
|
||||||
// The description text as fallback.
|
// The description text as fallback.
|
||||||
painter->setPen(textColor);
|
painter->setPen(descriptionTF.color());
|
||||||
painter->setFont(descriptionFont);
|
painter->setFont(descriptionTF.font());
|
||||||
painter->drawText(textArea, item->description, wrapped);
|
painter->drawText(thumbnailAreaR, item->description, wrapTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The description background
|
// The description background
|
||||||
|
QRect backgroundPortionR = bgR;
|
||||||
if (offset) {
|
if (offset) {
|
||||||
QRect backgroundPortionRect = tileRect;
|
backgroundPortionR.setTop(shiftY - offset);
|
||||||
backgroundPortionRect.setTop(shiftY - offset);
|
|
||||||
if (!pm.isNull()) {
|
if (!pm.isNull()) {
|
||||||
if (m_blurredThumbnail.isNull()) {
|
if (m_blurredThumbnail.isNull()) {
|
||||||
constexpr int blurRadius = 50;
|
constexpr int filterMargin = hoverBlurRadius;
|
||||||
QImage thumbnail(tileRect.size() + QSize(blurRadius, blurRadius) * 2,
|
QImage thumbnail(bgR.size() + QSize(filterMargin, filterMargin) * 2,
|
||||||
QImage::Format_ARGB32_Premultiplied);
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
thumbnail.fill(hoverColor);
|
thumbnail.fill(themeColor(Theme::Token_Foreground_Muted));
|
||||||
QPainter thumbnailPainter(&thumbnail);
|
QPainter thumbnailPainter(&thumbnail);
|
||||||
thumbnailPainter.translate(blurRadius, blurRadius);
|
thumbnailPainter.translate(filterMargin, filterMargin);
|
||||||
thumbnailPainter.fillRect(thumbnailBgRect, backgroundSecondaryColor);
|
thumbnailPainter.fillRect(thumbnailAreaR,
|
||||||
|
themeColor(Theme::Token_Background_Default));
|
||||||
thumbnailPainter.drawPixmap(thumbnailPos, pm);
|
thumbnailPainter.drawPixmap(thumbnailPos, pm);
|
||||||
thumbnailPainter.setPen(foregroundPrimaryColor);
|
thumbnailPainter.setPen(titleTF.color());
|
||||||
drawPixmapOverlay(item, &thumbnailPainter, option, thumbnailBgRect);
|
drawPixmapOverlay(item, &thumbnailPainter, option, thumbnailAreaR);
|
||||||
|
thumbnailPainter.setOpacity(1.0 - hoverBlurOpacity);
|
||||||
|
thumbnailPainter.fillRect(thumbnail.rect(),
|
||||||
|
themeColor(Theme::Token_Foreground_Muted));
|
||||||
thumbnailPainter.end();
|
thumbnailPainter.end();
|
||||||
|
qt_blurImage(thumbnail, hoverBlurRadius, false, false);
|
||||||
|
|
||||||
m_blurredThumbnail = QPixmap(tileRect.size());
|
QImage mask(thumbnail.size(), QImage::Format_Grayscale8);
|
||||||
QPainter blurredThumbnailPainter(&m_blurredThumbnail);
|
mask.fill(Qt::black);
|
||||||
blurredThumbnailPainter.translate(-blurRadius, -blurRadius);
|
QPainter maskPainter(&mask);
|
||||||
qt_blurImage(&blurredThumbnailPainter, thumbnail, blurRadius, false, false);
|
const QRect maskR = bgR.translated(filterMargin, filterMargin)
|
||||||
blurredThumbnailPainter.setOpacity(0.825);
|
.adjusted(1, 1, -1, -1);
|
||||||
blurredThumbnailPainter.fillRect(tileRect, hoverColor);
|
WelcomePageHelpers::drawCardBackground(&maskPainter, maskR,
|
||||||
|
Qt::white, Qt::NoPen, itemCornerRounding);
|
||||||
|
thumbnail.setAlphaChannel(mask);
|
||||||
|
|
||||||
|
m_blurredThumbnail = QPixmap::fromImage(
|
||||||
|
thumbnail.copy({filterMargin, filterMargin, bgR.width(), bgR.height()}));
|
||||||
}
|
}
|
||||||
const QPixmap thumbnailPortionPM = m_blurredThumbnail.copy(backgroundPortionRect);
|
const QPixmap thumbnailPortionPM = m_blurredThumbnail.copy(backgroundPortionR);
|
||||||
painter->drawPixmap(backgroundPortionRect.topLeft(), thumbnailPortionPM);
|
painter->drawPixmap(backgroundPortionR.topLeft(), thumbnailPortionPM);
|
||||||
} else {
|
} else {
|
||||||
painter->fillRect(backgroundPortionRect, hoverColor);
|
painter->fillRect(thumbnailAreaR, themeColor(Theme::Token_Foreground_Muted));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The description Text (unhovered or hovered)
|
// The description Text (unhovered or hovered)
|
||||||
painter->setPen(textColor);
|
painter->setPen(titleTF.color());
|
||||||
painter->setFont(sizedFont(13, option.widget)); // Title font
|
painter->setFont(titleTF.font());
|
||||||
if (offset) {
|
if (offset) {
|
||||||
// The title of the example
|
// The title of the example
|
||||||
const QRectF nameRect = painter->boundingRect(shiftedTextRect, item->name, wrapped);
|
const QRect shiftedTitleR = thumbnailAreaR.translated(backgroundPortionR.topLeft());
|
||||||
painter->drawText(nameRect, item->name, wrapped);
|
const QRect titleR = painter->boundingRect(shiftedTitleR, item->name, wrapTO).toRect();
|
||||||
|
painter->drawText(shiftedTitleR, item->name, wrapTO);
|
||||||
|
|
||||||
|
painter->setOpacity(animationProgress); // "fade in" separator line and description
|
||||||
|
|
||||||
// The separator line below the example title.
|
// The separator line below the example title.
|
||||||
const int ll = nameRect.height() + 3;
|
const QRect hrR(titleR.x(), titleR.bottom() + 1 + ExPaddingGapS, thumbnailAreaR.width(), 1);
|
||||||
const QLine line = QLine(0, ll, textArea.width(), ll).translated(shiftedTextRect.topLeft());
|
painter->fillRect(hrR, themeColor(Theme::Token_Stroke_Muted));
|
||||||
painter->setPen(foregroundSecondaryColor);
|
|
||||||
painter->setOpacity(animationProgress); // "fade in" separator line and description
|
|
||||||
painter->drawLine(line);
|
|
||||||
|
|
||||||
// The description text.
|
// The description text.
|
||||||
const int dd = ll + 5;
|
const QRect descriptionR(hrR.x(), hrR.bottom() + 1 + ExPaddingGapS,
|
||||||
const QRect descRect = shiftedTextRect.adjusted(0, dd, 0, dd);
|
thumbnailAreaR.width(), shiftY);
|
||||||
painter->setPen(textColor);
|
painter->setPen(descriptionTF.color());
|
||||||
painter->setFont(descriptionFont);
|
painter->setFont(descriptionTF.font());
|
||||||
painter->drawText(descRect, item->description, wrapped);
|
painter->drawText(descriptionR, item->description, wrapTO);
|
||||||
painter->setOpacity(1);
|
painter->setOpacity(1);
|
||||||
} else {
|
} else {
|
||||||
// The title of the example
|
// The title of the example
|
||||||
const QString elidedName = painter->fontMetrics()
|
const QString elidedName = painter->fontMetrics()
|
||||||
.elidedText(item->name, Qt::ElideRight, textRect.width());
|
.elidedText(item->name, Qt::ElideRight, titleR.width());
|
||||||
painter->drawText(textRect, elidedName);
|
painter->drawText(titleR, titleTF.drawTextFlags, elidedName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Separator line between text and 'Tags:' section
|
|
||||||
painter->setPen(foregroundSecondaryColor);
|
|
||||||
painter->drawLine(QLineF(textArea.topLeft(), textArea.topRight())
|
|
||||||
.translated(0, TagsSeparatorY));
|
|
||||||
|
|
||||||
// The 'Tags:' section
|
// The 'Tags:' section
|
||||||
painter->setPen(foregroundPrimaryColor);
|
painter->setPen(tagsLabelTF.color());
|
||||||
const QFont tagsFont = sizedFont(10, option.widget);
|
painter->setFont(tagsLabelTF.font());
|
||||||
painter->setFont(tagsFont);
|
painter->drawText(tagsLabelR, tagsLabelTF.drawTextFlags, tagsLabelText);
|
||||||
const QFontMetrics fm = painter->fontMetrics();
|
|
||||||
const QString tagsLabelText = Tr::tr("Tags:");
|
|
||||||
constexpr int tagsHorSpacing = 5;
|
|
||||||
const QRect tagsLabelRect =
|
|
||||||
QRect(0, 0, fm.horizontalAdvance(tagsLabelText) + tagsHorSpacing, fm.height())
|
|
||||||
.translated(textArea.x(), tagsBase);
|
|
||||||
painter->drawText(tagsLabelRect, tagsLabelText);
|
|
||||||
|
|
||||||
painter->setPen(themeColor(Theme::Welcome_LinkColor));
|
const QFontMetrics fm = painter->fontMetrics();
|
||||||
int emptyTagRowsLeft = 2;
|
|
||||||
|
painter->setPen(tagsTF.color());
|
||||||
|
painter->setFont(tagsTF.font());
|
||||||
|
int emptyTagRowsLeft = tagsRowsCount;
|
||||||
int xx = 0;
|
int xx = 0;
|
||||||
int yy = 0;
|
int yy = 0;
|
||||||
const bool populateTagsRects = m_currentTagRects.empty();
|
const bool populateTagsRects = m_currentTagRects.empty();
|
||||||
for (const QString &tag : item->tags) {
|
for (const QString &tag : item->tags) {
|
||||||
const int ww = fm.horizontalAdvance(tag) + tagsHorSpacing;
|
const int ww = fm.horizontalAdvance(tag);
|
||||||
if (xx + ww > textArea.width() - tagsLabelRect.width()) {
|
if (xx + ww > tagsR.width()) {
|
||||||
if (--emptyTagRowsLeft == 0)
|
if (--emptyTagRowsLeft == 0)
|
||||||
break;
|
break;
|
||||||
yy += fm.lineSpacing();
|
yy += fm.lineSpacing();
|
||||||
xx = 0;
|
xx = 0;
|
||||||
}
|
}
|
||||||
const QRect tagRect = QRect(xx, yy, ww, tagsLabelRect.height())
|
const QRect tagRect = QRect(xx, yy, ww, tagsLabelR.height()).translated(tagsR.topLeft());
|
||||||
.translated(tagsLabelRect.topRight());
|
painter->drawText(tagRect, tagsTF.drawTextFlags, tag);
|
||||||
painter->drawText(tagRect, tag);
|
if (populateTagsRects) {
|
||||||
if (populateTagsRects)
|
constexpr int grow = tagsHGap / 2;
|
||||||
m_currentTagRects.append({ tag, tagRect });
|
const QRect tagMouseArea = tagRect.adjusted(-grow, -grow, grow, grow);
|
||||||
xx += ww;
|
m_currentTagRects.append({ tag, tagMouseArea });
|
||||||
|
}
|
||||||
|
xx += ww + tagsHGap;
|
||||||
}
|
}
|
||||||
|
|
||||||
painter->restore();
|
painter->restore();
|
||||||
@@ -642,7 +1041,7 @@ bool ListItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
|
|||||||
|
|
||||||
QSize ListItemDelegate::sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const
|
QSize ListItemDelegate::sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const
|
||||||
{
|
{
|
||||||
return {GridItemWidth, GridItemHeight};
|
return itemSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListItemDelegate::drawPixmapOverlay(const ListItem *, QPainter *,
|
void ListItemDelegate::drawPixmapOverlay(const ListItem *, QPainter *,
|
||||||
@@ -682,6 +1081,7 @@ SectionedGridView::SectionedGridView(QWidget *parent)
|
|||||||
|
|
||||||
auto sectionedView = new QWidget;
|
auto sectionedView = new QWidget;
|
||||||
auto layout = new QVBoxLayout;
|
auto layout = new QVBoxLayout;
|
||||||
|
layout->setSpacing(0);
|
||||||
layout->setContentsMargins(0, 0, 0, 0);
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
layout->addStretch(1);
|
layout->addStretch(1);
|
||||||
sectionedView->setLayout(layout);
|
sectionedView->setLayout(layout);
|
||||||
@@ -744,24 +1144,24 @@ void SectionedGridView::setSearchString(const QString &searchString)
|
|||||||
filterModel->setSearchString(searchString);
|
filterModel->setSearchString(searchString);
|
||||||
}
|
}
|
||||||
|
|
||||||
static QWidget *createSeparator(QWidget *parent)
|
static QLabel *createTitleLabel(const QString &text, QWidget *parent = nullptr)
|
||||||
{
|
{
|
||||||
QWidget *line = Layouting::createHr(parent);
|
constexpr TextFormat headerTitleTF {Theme::Token_Text_Muted, StyleHelper::UiElementH4};
|
||||||
QSizePolicy linePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored);
|
auto link = new QLabel(text, parent);
|
||||||
linePolicy.setHorizontalStretch(2);
|
link->setFont(headerTitleTF.font());
|
||||||
line->setSizePolicy(linePolicy);
|
QPalette pal = link->palette();
|
||||||
QPalette pal = line->palette();
|
pal.setColor(QPalette::WindowText, headerTitleTF.color());
|
||||||
pal.setColor(QPalette::Dark, Qt::transparent);
|
link->setPalette(pal);
|
||||||
pal.setColor(QPalette::Light, themeColor(Theme::Welcome_ForegroundSecondaryColor));
|
return link;
|
||||||
line->setPalette(pal);
|
|
||||||
return line;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static QLabel *createLinkLabel(const QString &text, QWidget *parent)
|
static QLabel *createLinkLabel(const QString &text, QWidget *parent)
|
||||||
{
|
{
|
||||||
const QString linkColor = themeColor(Theme::Welcome_LinkColor).name();
|
constexpr TextFormat headerLinkTF {Theme::Token_Accent_Default, StyleHelper::UiElementH6};
|
||||||
|
const QString linkColor = themeColor(headerLinkTF.themeColor).name();
|
||||||
auto link = new QLabel("<a href=\"link\" style=\"color: " + linkColor + ";\">"
|
auto link = new QLabel("<a href=\"link\" style=\"color: " + linkColor + ";\">"
|
||||||
+ text + "</a>", parent);
|
+ text + "</a>", parent);
|
||||||
|
link->setFont(headerLinkTF.font());
|
||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -797,14 +1197,13 @@ ListModel *SectionedGridView::addSection(const Section §ion, const QList<Lis
|
|||||||
connect(seeAllLink, &QLabel::linkActivated, this, [this, section] { zoomInSection(section); });
|
connect(seeAllLink, &QLabel::linkActivated, this, [this, section] { zoomInSection(section); });
|
||||||
using namespace Layouting;
|
using namespace Layouting;
|
||||||
QWidget *sectionLabel = Row {
|
QWidget *sectionLabel = Row {
|
||||||
section.name,
|
createTitleLabel(section.name),
|
||||||
createSeparator(this),
|
st,
|
||||||
seeAllLink,
|
seeAllLink,
|
||||||
Space(HSpacing),
|
Space(ExVPaddingGapXl),
|
||||||
noMargin
|
customMargin({0, ExPaddingGapL, 0, VPaddingL}),
|
||||||
}.emerge();
|
}.emerge();
|
||||||
m_sectionLabels.append(sectionLabel);
|
m_sectionLabels.append(sectionLabel);
|
||||||
sectionLabel->setContentsMargins(0, ItemGap, 0, 0);
|
|
||||||
auto scrollArea = qobject_cast<QScrollArea *>(widget(0));
|
auto scrollArea = qobject_cast<QScrollArea *>(widget(0));
|
||||||
auto vbox = qobject_cast<QVBoxLayout *>(scrollArea->widget()->layout());
|
auto vbox = qobject_cast<QVBoxLayout *>(scrollArea->widget()->layout());
|
||||||
|
|
||||||
@@ -858,6 +1257,7 @@ void SectionedGridView::zoomInSection(const Section §ion)
|
|||||||
auto zoomedInWidget = new QWidget(this);
|
auto zoomedInWidget = new QWidget(this);
|
||||||
auto layout = new QVBoxLayout;
|
auto layout = new QVBoxLayout;
|
||||||
layout->setContentsMargins(0, 0, 0, 0);
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
layout->setSpacing(0);
|
||||||
zoomedInWidget->setLayout(layout);
|
zoomedInWidget->setLayout(layout);
|
||||||
|
|
||||||
QLabel *backLink = createLinkLabel("< " + Tr::tr("Back"), this);
|
QLabel *backLink = createLinkLabel("< " + Tr::tr("Back"), this);
|
||||||
@@ -868,13 +1268,12 @@ void SectionedGridView::zoomInSection(const Section §ion)
|
|||||||
});
|
});
|
||||||
using namespace Layouting;
|
using namespace Layouting;
|
||||||
QWidget *sectionLabel = Row {
|
QWidget *sectionLabel = Row {
|
||||||
section.name,
|
createTitleLabel(section.name),
|
||||||
createSeparator(this),
|
st,
|
||||||
backLink,
|
backLink,
|
||||||
Space(HSpacing),
|
Space(ExVPaddingGapXl),
|
||||||
noMargin
|
customMargin({0, ExPaddingGapL, 0, VPaddingL}),
|
||||||
}.emerge();
|
}.emerge();
|
||||||
sectionLabel->setContentsMargins(0, ItemGap, 0, 0);
|
|
||||||
|
|
||||||
auto gridView = new GridView(zoomedInWidget);
|
auto gridView = new GridView(zoomedInWidget);
|
||||||
gridView->setItemDelegate(m_itemDelegate);
|
gridView->setItemDelegate(m_itemDelegate);
|
||||||
|
@@ -6,10 +6,17 @@
|
|||||||
#include "core_global.h"
|
#include "core_global.h"
|
||||||
#include "iwelcomepage.h"
|
#include "iwelcomepage.h"
|
||||||
|
|
||||||
|
#include <utils/fancylineedit.h>
|
||||||
|
#include <utils/stylehelper.h>
|
||||||
|
#include <utils/theme/theme.h>
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
|
#include <QLabel>
|
||||||
#include <QListView>
|
#include <QListView>
|
||||||
#include <QPen>
|
#include <QPen>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
#include <QPushButton>
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
#include <QStackedWidget>
|
#include <QStackedWidget>
|
||||||
#include <QStyledItemDelegate>
|
#include <QStyledItemDelegate>
|
||||||
@@ -24,31 +31,111 @@ namespace Core {
|
|||||||
|
|
||||||
namespace WelcomePageHelpers {
|
namespace WelcomePageHelpers {
|
||||||
|
|
||||||
constexpr int HSpacing = 20;
|
constexpr QSize WelcomeThumbnailSize(214, 160);
|
||||||
constexpr int ItemGap = 4;
|
|
||||||
|
|
||||||
constexpr int GridItemGap = 3 * ItemGap;
|
class CORE_EXPORT TextFormat {
|
||||||
constexpr int GridItemWidth = 240 + GridItemGap; // Extra GridItemGap as "spacing"
|
public:
|
||||||
constexpr int GridItemHeight = GridItemWidth;
|
QColor color() const
|
||||||
constexpr QSize GridItemImageSize(GridItemWidth - GridItemGap
|
{
|
||||||
- 2 * (GridItemGap + 1), // Horizontal margins + 1 pixel
|
return Utils::creatorTheme()->color(themeColor);
|
||||||
GridItemHeight - GridItemGap
|
}
|
||||||
- GridItemGap - 1 // Upper margin + 1 pixel
|
|
||||||
- 67); // Bottom margin (for title + tags)
|
|
||||||
|
|
||||||
CORE_EXPORT QWidget *panelBar(QWidget *parent = nullptr);
|
QFont font(bool underlined = false) const
|
||||||
|
{
|
||||||
|
QFont result = Utils::StyleHelper::uiFont(uiElement);
|
||||||
|
result.setUnderline(underlined);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lineHeight() const
|
||||||
|
{
|
||||||
|
return Utils::StyleHelper::uiFontLineHeight(uiElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Utils::Theme::Color themeColor;
|
||||||
|
const Utils::StyleHelper::UiElement uiElement;
|
||||||
|
const int drawTextFlags = Qt::AlignLeft | Qt::AlignBottom | Qt::TextDontClip;
|
||||||
|
};
|
||||||
|
|
||||||
|
CORE_EXPORT void setBackgroundColor(QWidget *widget, Utils::Theme::Color colorRole);
|
||||||
|
constexpr qreal defaultCardBackgroundRounding = 3.75;
|
||||||
CORE_EXPORT void drawCardBackground(QPainter *painter, const QRectF &rect,
|
CORE_EXPORT void drawCardBackground(QPainter *painter, const QRectF &rect,
|
||||||
const QBrush &fill, const QPen &pen = QPen(Qt::NoPen),
|
const QBrush &fill, const QPen &pen = QPen(Qt::NoPen),
|
||||||
qreal rounding = 5.0);
|
qreal rounding = defaultCardBackgroundRounding);
|
||||||
|
CORE_EXPORT QWidget *createRule(Qt::Orientation orientation, QWidget *parent = nullptr);
|
||||||
|
|
||||||
} // namespace WelcomePageHelpers
|
} // namespace WelcomePageHelpers
|
||||||
|
|
||||||
class CORE_EXPORT SearchBox : public WelcomePageFrame
|
class CORE_EXPORT Button : public QPushButton
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Role {
|
||||||
|
MediumPrimary,
|
||||||
|
MediumSecondary,
|
||||||
|
SmallPrimary,
|
||||||
|
SmallSecondary,
|
||||||
|
SmallList,
|
||||||
|
SmallLink,
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit Button(const QString &text, Role role, QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
QSize minimumSizeHint() const override;
|
||||||
|
|
||||||
|
void setPixmap(const QPixmap &newPixmap);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateMargins();
|
||||||
|
|
||||||
|
const Role m_role = MediumPrimary;
|
||||||
|
QPixmap m_pixmap;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CORE_EXPORT Label : public QLabel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Role {
|
||||||
|
Primary,
|
||||||
|
Secondary,
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit Label(const QString &text, Role role, QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Role m_role = Primary;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CORE_EXPORT SearchBox : public QLineEdit
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit SearchBox(QWidget *parent = nullptr);
|
explicit SearchBox(QWidget *parent = nullptr);
|
||||||
|
|
||||||
Utils::FancyLineEdit *m_lineEdit = nullptr;
|
QSize minimumSizeHint() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void enterEvent(QEnterEvent *event) override;
|
||||||
|
void leaveEvent(QEvent *event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CORE_EXPORT ComboBox : public QComboBox
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ComboBox(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
QSize sizeHint() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void enterEvent(QEnterEvent *event) override;
|
||||||
|
void leaveEvent(QEvent *event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CORE_EXPORT GridView : public QListView
|
class CORE_EXPORT GridView : public QListView
|
||||||
@@ -146,7 +233,9 @@ class CORE_EXPORT ListItemDelegate : public QStyledItemDelegate
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
ListItemDelegate();
|
ListItemDelegate() = default;
|
||||||
|
|
||||||
|
static QSize itemSize();
|
||||||
void paint(QPainter *painter, const QStyleOptionViewItem &option,
|
void paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||||
const QModelIndex &index) const override;
|
const QModelIndex &index) const override;
|
||||||
|
|
||||||
@@ -165,13 +254,6 @@ protected:
|
|||||||
|
|
||||||
void goon();
|
void goon();
|
||||||
|
|
||||||
const QColor backgroundPrimaryColor;
|
|
||||||
const QColor backgroundSecondaryColor;
|
|
||||||
const QColor foregroundPrimaryColor;
|
|
||||||
const QColor foregroundSecondaryColor;
|
|
||||||
const QColor hoverColor;
|
|
||||||
const QColor textColor;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable QPersistentModelIndex m_previousIndex;
|
mutable QPersistentModelIndex m_previousIndex;
|
||||||
mutable QElapsedTimer m_startTime;
|
mutable QElapsedTimer m_startTime;
|
||||||
|
@@ -29,14 +29,6 @@ using namespace Utils;
|
|||||||
|
|
||||||
namespace ExtensionManager::Internal {
|
namespace ExtensionManager::Internal {
|
||||||
|
|
||||||
static QWidget *createVr(QWidget *parent = nullptr)
|
|
||||||
{
|
|
||||||
auto vr = new QWidget(parent);
|
|
||||||
vr->setFixedWidth(1);
|
|
||||||
setBackgroundColor(vr, Theme::Token_Stroke_Subtle);
|
|
||||||
return vr;
|
|
||||||
}
|
|
||||||
|
|
||||||
class CollapsingWidget : public QWidget
|
class CollapsingWidget : public QWidget
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -79,13 +71,13 @@ ExtensionManagerWidget::ExtensionManagerWidget()
|
|||||||
|
|
||||||
using namespace Layouting;
|
using namespace Layouting;
|
||||||
Row {
|
Row {
|
||||||
createVr(),
|
WelcomePageHelpers::createRule(Qt::Vertical),
|
||||||
m_secondaryDescription,
|
m_secondaryDescription,
|
||||||
noMargin(), spacing(0),
|
noMargin(), spacing(0),
|
||||||
}.attachTo(m_secondarDescriptionWidget);
|
}.attachTo(m_secondarDescriptionWidget);
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
createVr(),
|
WelcomePageHelpers::createRule(Qt::Vertical),
|
||||||
Row {
|
Row {
|
||||||
m_primaryDescription,
|
m_primaryDescription,
|
||||||
noMargin(),
|
noMargin(),
|
||||||
@@ -95,13 +87,13 @@ ExtensionManagerWidget::ExtensionManagerWidget()
|
|||||||
}.attachTo(descriptionColumns);
|
}.attachTo(descriptionColumns);
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
Space(WelcomePageHelpers::HSpacing),
|
Space(StyleHelper::SpacingTokens::ExVPaddingGapXl),
|
||||||
m_leftColumn,
|
m_leftColumn,
|
||||||
descriptionColumns,
|
descriptionColumns,
|
||||||
noMargin(), spacing(0),
|
noMargin(), spacing(0),
|
||||||
}.attachTo(this);
|
}.attachTo(this);
|
||||||
|
|
||||||
setBackgroundColor(this, Theme::Token_Background_Default);
|
WelcomePageHelpers::setBackgroundColor(this, Theme::Token_Background_Default);
|
||||||
|
|
||||||
connect(m_leftColumn, &ExtensionsBrowser::itemSelected,
|
connect(m_leftColumn, &ExtensionsBrowser::itemSelected,
|
||||||
this, &ExtensionManagerWidget::updateView);
|
this, &ExtensionManagerWidget::updateView);
|
||||||
@@ -132,7 +124,7 @@ void ExtensionManagerWidget::updateView(const QModelIndex ¤t,
|
|||||||
"margin-left: %3px; margin-right: %3px;")
|
"margin-left: %3px; margin-right: %3px;")
|
||||||
.arg(creatorTheme()->color(Theme::Token_Text_Default).name())
|
.arg(creatorTheme()->color(Theme::Token_Text_Default).name())
|
||||||
.arg(creatorTheme()->color(Theme::Token_Background_Muted).name())
|
.arg(creatorTheme()->color(Theme::Token_Background_Muted).name())
|
||||||
.arg(WelcomePageHelpers::HSpacing);
|
.arg(StyleHelper::SpacingTokens::ExVPaddingGapXl);
|
||||||
const QString htmlStart = QString(R"(
|
const QString htmlStart = QString(R"(
|
||||||
<html>
|
<html>
|
||||||
<body style="%1">
|
<body style="%1">
|
||||||
|
@@ -41,7 +41,7 @@ using PluginSpecList = QList<const PluginSpec *>;
|
|||||||
using Tags = QStringList;
|
using Tags = QStringList;
|
||||||
|
|
||||||
constexpr QSize itemSize = {330, 86};
|
constexpr QSize itemSize = {330, 86};
|
||||||
constexpr int gapSize = 2 * WelcomePageHelpers::GridItemGap;
|
constexpr int gapSize = StyleHelper::SpacingTokens::ExVPaddingGapXl;
|
||||||
constexpr QSize cellSize = {itemSize.width() + gapSize, itemSize.height() + gapSize};
|
constexpr QSize cellSize = {itemSize.width() + gapSize, itemSize.height() + gapSize};
|
||||||
|
|
||||||
enum Role {
|
enum Role {
|
||||||
@@ -62,16 +62,6 @@ ItemData itemData(const QModelIndex &index)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBackgroundColor(QWidget *widget, Theme::Color colorRole)
|
|
||||||
{
|
|
||||||
QPalette palette = creatorTheme()->palette();
|
|
||||||
palette.setColor(QPalette::Window,
|
|
||||||
creatorTheme()->color(colorRole));
|
|
||||||
widget->setPalette(palette);
|
|
||||||
widget->setBackgroundRole(QPalette::Window);
|
|
||||||
widget->setAutoFillBackground(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static QColor colorForExtensionName(const QString &name)
|
static QColor colorForExtensionName(const QString &name)
|
||||||
{
|
{
|
||||||
const size_t hash = qHash(name);
|
const size_t hash = qHash(name);
|
||||||
@@ -390,7 +380,7 @@ public:
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
constexpr int textX = 80;
|
constexpr int textX = 80;
|
||||||
constexpr int rightMargin = 2 * WelcomePageHelpers::ItemGap;
|
constexpr int rightMargin = StyleHelper::SpacingTokens::ExVPaddingGapXl;
|
||||||
constexpr int maxTextWidth = itemSize.width() - textX - rightMargin;
|
constexpr int maxTextWidth = itemSize.width() - textX - rightMargin;
|
||||||
constexpr Qt::TextElideMode elideMode = Qt::ElideRight;
|
constexpr Qt::TextElideMode elideMode = Qt::ElideRight;
|
||||||
|
|
||||||
@@ -440,8 +430,7 @@ ExtensionsBrowser::ExtensionsBrowser()
|
|||||||
m_searchBox = new Core::SearchBox;
|
m_searchBox = new Core::SearchBox;
|
||||||
m_searchBox->setFixedWidth(itemSize.width());
|
m_searchBox->setFixedWidth(itemSize.width());
|
||||||
|
|
||||||
m_updateButton = new WelcomePageButton;
|
m_updateButton = new Button(Tr::tr("Install..."), Button::MediumPrimary);
|
||||||
m_updateButton->setText(Tr::tr("Install..."));
|
|
||||||
|
|
||||||
m_filterProxyModel = new QSortFilterProxyModel(this);
|
m_filterProxyModel = new QSortFilterProxyModel(this);
|
||||||
m_filterProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
m_filterProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||||
@@ -469,9 +458,10 @@ ExtensionsBrowser::ExtensionsBrowser()
|
|||||||
noMargin(), spacing(0),
|
noMargin(), spacing(0),
|
||||||
}.attachTo(this);
|
}.attachTo(this);
|
||||||
|
|
||||||
setBackgroundColor(this, Theme::Token_Background_Default);
|
WelcomePageHelpers::setBackgroundColor(this, Theme::Token_Background_Default);
|
||||||
setBackgroundColor(m_extensionsView, Theme::Token_Background_Default);
|
WelcomePageHelpers::setBackgroundColor(m_extensionsView, Theme::Token_Background_Default);
|
||||||
setBackgroundColor(m_extensionsView->viewport(), Theme::Token_Background_Default);
|
WelcomePageHelpers::setBackgroundColor(m_extensionsView->viewport(),
|
||||||
|
Theme::Token_Background_Default);
|
||||||
|
|
||||||
auto updateModel = [this] {
|
auto updateModel = [this] {
|
||||||
m_model.reset(extensionsModel());
|
m_model.reset(extensionsModel());
|
||||||
@@ -488,7 +478,7 @@ ExtensionsBrowser::ExtensionsBrowser()
|
|||||||
|
|
||||||
connect(ExtensionSystem::PluginManager::instance(),
|
connect(ExtensionSystem::PluginManager::instance(),
|
||||||
&ExtensionSystem::PluginManager::pluginsChanged, this, updateModel);
|
&ExtensionSystem::PluginManager::pluginsChanged, this, updateModel);
|
||||||
connect(m_searchBox->m_lineEdit, &Utils::FancyLineEdit::textChanged,
|
connect(m_searchBox, &QLineEdit::textChanged,
|
||||||
m_filterProxyModel, &QSortFilterProxyModel::setFilterWildcard);
|
m_filterProxyModel, &QSortFilterProxyModel::setFilterWildcard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,7 +10,9 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QItemSelectionModel;
|
class QItemSelectionModel;
|
||||||
|
class QLineEdit;
|
||||||
class QListView;
|
class QListView;
|
||||||
|
class QPushButton;
|
||||||
class QSortFilterProxyModel;
|
class QSortFilterProxyModel;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
@@ -19,11 +21,6 @@ namespace ExtensionSystem
|
|||||||
class PluginSpec;
|
class PluginSpec;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Core {
|
|
||||||
class SearchBox;
|
|
||||||
class WelcomePageButton;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ExtensionManager::Internal {
|
namespace ExtensionManager::Internal {
|
||||||
|
|
||||||
using PluginSpecList = QList<const ExtensionSystem::PluginSpec *>;
|
using PluginSpecList = QList<const ExtensionSystem::PluginSpec *>;
|
||||||
@@ -42,7 +39,6 @@ struct ItemData {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ItemData itemData(const QModelIndex &index);
|
ItemData itemData(const QModelIndex &index);
|
||||||
void setBackgroundColor(QWidget *widget, Utils::Theme::Color colorRole);
|
|
||||||
|
|
||||||
class ExtensionsBrowser final : public QWidget
|
class ExtensionsBrowser final : public QWidget
|
||||||
{
|
{
|
||||||
@@ -61,8 +57,8 @@ private:
|
|||||||
int extraListViewWidth() const; // Space for scrollbar, etc.
|
int extraListViewWidth() const; // Space for scrollbar, etc.
|
||||||
|
|
||||||
QScopedPointer<QStandardItemModel> m_model;
|
QScopedPointer<QStandardItemModel> m_model;
|
||||||
Core::SearchBox *m_searchBox;
|
QLineEdit *m_searchBox;
|
||||||
Core::WelcomePageButton *m_updateButton;
|
QPushButton *m_updateButton;
|
||||||
QListView *m_extensionsView;
|
QListView *m_extensionsView;
|
||||||
QItemSelectionModel *m_selectionModel = nullptr;
|
QItemSelectionModel *m_selectionModel = nullptr;
|
||||||
QSortFilterProxyModel *m_filterProxyModel;
|
QSortFilterProxyModel *m_filterProxyModel;
|
||||||
|
@@ -269,7 +269,7 @@ void SectionedProducts::onImageDownloadFinished(QNetworkReply *reply)
|
|||||||
if (pixmap.loadFromData(data, imageFormat.toLatin1())) {
|
if (pixmap.loadFromData(data, imageFormat.toLatin1())) {
|
||||||
const QString url = imageUrl.toString();
|
const QString url = imageUrl.toString();
|
||||||
const int dpr = qApp->devicePixelRatio();
|
const int dpr = qApp->devicePixelRatio();
|
||||||
pixmap = pixmap.scaled(WelcomePageHelpers::GridItemImageSize * dpr,
|
pixmap = pixmap.scaled(WelcomePageHelpers::WelcomeThumbnailSize * dpr,
|
||||||
Qt::KeepAspectRatio,
|
Qt::KeepAspectRatio,
|
||||||
Qt::SmoothTransformation);
|
Qt::SmoothTransformation);
|
||||||
pixmap.setDevicePixelRatio(dpr);
|
pixmap.setDevicePixelRatio(dpr);
|
||||||
|
@@ -9,9 +9,10 @@
|
|||||||
#include <coreplugin/welcomepagehelper.h>
|
#include <coreplugin/welcomepagehelper.h>
|
||||||
|
|
||||||
#include <utils/fancylineedit.h>
|
#include <utils/fancylineedit.h>
|
||||||
|
#include <utils/layoutbuilder.h>
|
||||||
#include <utils/progressindicator.h>
|
#include <utils/progressindicator.h>
|
||||||
#include <utils/theme/theme.h>
|
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/theme/theme.h>
|
||||||
|
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
@@ -44,38 +45,34 @@ class QtMarketplacePageWidget : public QWidget
|
|||||||
public:
|
public:
|
||||||
QtMarketplacePageWidget()
|
QtMarketplacePageWidget()
|
||||||
{
|
{
|
||||||
auto searchBox = new Core::SearchBox(this);
|
m_searcher = new Core::SearchBox(this);
|
||||||
m_searcher = searchBox->m_lineEdit;
|
|
||||||
m_searcher->setPlaceholderText(Tr::tr("Search in Marketplace..."));
|
m_searcher->setPlaceholderText(Tr::tr("Search in Marketplace..."));
|
||||||
|
|
||||||
auto vbox = new QVBoxLayout(this);
|
|
||||||
vbox->setContentsMargins(0, 0, 0, Core::WelcomePageHelpers::ItemGap);
|
|
||||||
vbox->setSpacing(Core::WelcomePageHelpers::ItemGap);
|
|
||||||
|
|
||||||
auto searchBar = Core::WelcomePageHelpers::panelBar();
|
|
||||||
auto hbox = new QHBoxLayout(searchBar);
|
|
||||||
hbox->setContentsMargins(Core::WelcomePageHelpers::HSpacing, 0,
|
|
||||||
Core::WelcomePageHelpers::HSpacing, 0);
|
|
||||||
hbox->addWidget(searchBox);
|
|
||||||
vbox->addWidget(searchBar);
|
|
||||||
m_errorLabel = new QLabel(this);
|
m_errorLabel = new QLabel(this);
|
||||||
m_errorLabel->setVisible(false);
|
m_errorLabel->setVisible(false);
|
||||||
vbox->addWidget(m_errorLabel);
|
|
||||||
|
|
||||||
auto resultWidget = new QWidget(this);
|
|
||||||
auto resultHBox = new QHBoxLayout(resultWidget);
|
|
||||||
resultHBox->setContentsMargins(Core::WelcomePageHelpers::HSpacing, 0, 0, 0);
|
|
||||||
m_sectionedProducts = new SectionedProducts(this);
|
m_sectionedProducts = new SectionedProducts(this);
|
||||||
auto progressIndicator = new Utils::ProgressIndicator(ProgressIndicatorSize::Large, this);
|
auto progressIndicator = new Utils::ProgressIndicator(ProgressIndicatorSize::Large, this);
|
||||||
progressIndicator->attachToWidget(m_sectionedProducts);
|
progressIndicator->attachToWidget(m_sectionedProducts);
|
||||||
progressIndicator->hide();
|
progressIndicator->hide();
|
||||||
resultHBox->addWidget(m_sectionedProducts);
|
|
||||||
vbox->addWidget(resultWidget);
|
using namespace StyleHelper::SpacingTokens;
|
||||||
|
|
||||||
|
using namespace Layouting;
|
||||||
|
Column {
|
||||||
|
Row {
|
||||||
|
m_searcher,
|
||||||
|
customMargin({0, 0, ExVPaddingGapXl, 0}),
|
||||||
|
},
|
||||||
|
m_sectionedProducts,
|
||||||
|
spacing(VPaddingL),
|
||||||
|
customMargin({ExVPaddingGapXl, ExVPaddingGapXl, 0, 0}),
|
||||||
|
}.attachTo(this);
|
||||||
|
|
||||||
connect(m_sectionedProducts, &SectionedProducts::toggleProgressIndicator,
|
connect(m_sectionedProducts, &SectionedProducts::toggleProgressIndicator,
|
||||||
progressIndicator, &Utils::ProgressIndicator::setVisible);
|
progressIndicator, &Utils::ProgressIndicator::setVisible);
|
||||||
connect(m_sectionedProducts, &SectionedProducts::errorOccurred, this,
|
connect(m_sectionedProducts, &SectionedProducts::errorOccurred, this,
|
||||||
[this, progressIndicator, searchBox](int, const QString &message) {
|
[this, progressIndicator](int, const QString &message) {
|
||||||
progressIndicator->hide();
|
progressIndicator->hide();
|
||||||
progressIndicator->deleteLater();
|
progressIndicator->deleteLater();
|
||||||
m_errorLabel->setAlignment(Qt::AlignHCenter);
|
m_errorLabel->setAlignment(Qt::AlignHCenter);
|
||||||
@@ -89,7 +86,7 @@ public:
|
|||||||
"</p><br/><p><small><i>Error: %1</i></small></p>").arg(message);
|
"</p><br/><p><small><i>Error: %1</i></small></p>").arg(message);
|
||||||
m_errorLabel->setText(txt);
|
m_errorLabel->setText(txt);
|
||||||
m_errorLabel->setVisible(true);
|
m_errorLabel->setVisible(true);
|
||||||
searchBox->setVisible(false);
|
m_searcher->setVisible(false);
|
||||||
connect(m_errorLabel, &QLabel::linkActivated,
|
connect(m_errorLabel, &QLabel::linkActivated,
|
||||||
this, []() { QDesktopServices::openUrl(QUrl("https://marketplace.qt.io")); });
|
this, []() { QDesktopServices::openUrl(QUrl("https://marketplace.qt.io")); });
|
||||||
});
|
});
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/icon.h>
|
#include <utils/icon.h>
|
||||||
|
#include <utils/layoutbuilder.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/stringutils.h>
|
#include <utils/stringutils.h>
|
||||||
#include <utils/stylehelper.h>
|
#include <utils/stylehelper.h>
|
||||||
@@ -28,9 +29,6 @@
|
|||||||
|
|
||||||
#include <QAbstractItemDelegate>
|
#include <QAbstractItemDelegate>
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QBoxLayout>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QHelpEvent>
|
#include <QHelpEvent>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
@@ -42,16 +40,52 @@
|
|||||||
using namespace Core;
|
using namespace Core;
|
||||||
using namespace Core::WelcomePageHelpers;
|
using namespace Core::WelcomePageHelpers;
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
using namespace Utils::StyleHelper::SpacingTokens;
|
||||||
|
|
||||||
const int LINK_HEIGHT = 35;
|
|
||||||
const int TEXT_OFFSET_HORIZONTAL = 36;
|
|
||||||
const int SESSION_LINE_HEIGHT = 28;
|
|
||||||
const int SESSION_ARROW_RECT_WIDTH = 24;
|
|
||||||
const char PROJECT_BASE_ID[] = "Welcome.OpenRecentProject";
|
const char PROJECT_BASE_ID[] = "Welcome.OpenRecentProject";
|
||||||
|
|
||||||
namespace ProjectExplorer {
|
namespace ProjectExplorer {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
constexpr TextFormat projectNameTF {Theme::Token_Accent_Default, StyleHelper::UiElementH5};
|
||||||
|
constexpr TextFormat projectPathTF {Theme::Token_Text_Muted, StyleHelper::UiElementIconActive};
|
||||||
|
constexpr TextFormat sessionNameTF {projectNameTF.themeColor, projectNameTF.uiElement};
|
||||||
|
constexpr TextFormat sessionProjetNameTF {Theme::Token_Text_Default, projectNameTF.uiElement};
|
||||||
|
constexpr TextFormat shortcutNumberTF {Theme::Token_Text_Default,
|
||||||
|
StyleHelper::UiElementCaptionStrong,
|
||||||
|
Qt::AlignCenter | Qt::TextDontClip};
|
||||||
|
constexpr TextFormat actionTF {Theme::Token_Text_Default, StyleHelper::UiElementIconActive,
|
||||||
|
Qt::AlignCenter | Qt::TextDontClip};
|
||||||
|
constexpr TextFormat actionDisabledTF {Theme::Token_Text_Subtle, actionTF.uiElement,
|
||||||
|
actionTF.drawTextFlags};
|
||||||
|
constexpr int shortcutNumberWidth = 16;
|
||||||
|
constexpr int actionSepWidth = 1;
|
||||||
|
constexpr int sessionScrollBarGap = HPaddingXs;
|
||||||
|
|
||||||
|
static int s(const int metric)
|
||||||
|
{
|
||||||
|
constexpr int shrinkWhenAbove = 150; // Above this session count, increasingly reduce scale
|
||||||
|
constexpr qreal maxScale = 1.0; // Spacings as defined by design
|
||||||
|
constexpr qreal minScale = 0.2; // Maximum "condensed" layout
|
||||||
|
|
||||||
|
const int sessionsCount = SessionManager::sessionsCount();
|
||||||
|
const qreal scaling = sessionsCount < shrinkWhenAbove
|
||||||
|
? maxScale
|
||||||
|
: qMax(minScale,
|
||||||
|
maxScale - (sessionsCount - shrinkWhenAbove) * 0.065);
|
||||||
|
return int(qMax(1.0, scaling * metric));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int itemSpacing()
|
||||||
|
{
|
||||||
|
return qMax(int(s(VGapL)), VGapS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool withIcon()
|
||||||
|
{
|
||||||
|
return s(100) > 60; // Hide icons if spacings are scaled to below 60%
|
||||||
|
}
|
||||||
|
|
||||||
ProjectModel::ProjectModel(QObject *parent)
|
ProjectModel::ProjectModel(QObject *parent)
|
||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
{
|
{
|
||||||
@@ -61,7 +95,7 @@ ProjectModel::ProjectModel(QObject *parent)
|
|||||||
|
|
||||||
int ProjectModel::rowCount(const QModelIndex &) const
|
int ProjectModel::rowCount(const QModelIndex &) const
|
||||||
{
|
{
|
||||||
return m_projects.count();
|
return int(m_projects.count());
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant ProjectModel::data(const QModelIndex &index, int role) const
|
QVariant ProjectModel::data(const QModelIndex &index, int role) const
|
||||||
@@ -190,21 +224,24 @@ static QColor themeColor(Theme::Color role)
|
|||||||
return Utils::creatorTheme()->color(role);
|
return Utils::creatorTheme()->color(role);
|
||||||
}
|
}
|
||||||
|
|
||||||
static QFont sizedFont(int size, const QWidget *widget,
|
static QPixmap pixmap(const QString &id, const Theme::Color color)
|
||||||
bool underline = false)
|
|
||||||
{
|
|
||||||
QFont f = widget->font();
|
|
||||||
f.setPixelSize(size);
|
|
||||||
f.setUnderline(underline);
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
static QPixmap pixmap(const QString &id, const Theme::Color &color)
|
|
||||||
{
|
{
|
||||||
const QString fileName = QString(":/welcome/images/%1.png").arg(id);
|
const QString fileName = QString(":/welcome/images/%1.png").arg(id);
|
||||||
return Icon({{FilePath::fromString(fileName), color}}, Icon::Tint).pixmap();
|
return Icon({{FilePath::fromString(fileName), color}}, Icon::Tint).pixmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void drawBackgroundRect(QPainter *painter, const QRectF &rect, bool hovered)
|
||||||
|
{
|
||||||
|
const QColor fill(themeColor(hovered ? Theme::Token_Foreground_Muted
|
||||||
|
: Theme::Token_Background_Muted));
|
||||||
|
const QPen pen(themeColor(hovered ? Theme::Token_Foreground_Muted
|
||||||
|
: Theme::Token_Stroke_Subtle));
|
||||||
|
|
||||||
|
const qreal rounding = s(defaultCardBackgroundRounding * 1000) / 1000.0;
|
||||||
|
const qreal saneRounding = rounding <= 2 ? 0 : rounding;
|
||||||
|
WelcomePageHelpers::drawCardBackground(painter, rect, fill, pen, saneRounding);
|
||||||
|
}
|
||||||
|
|
||||||
class BaseDelegate : public QAbstractItemDelegate
|
class BaseDelegate : public QAbstractItemDelegate
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
@@ -244,6 +281,11 @@ protected:
|
|||||||
class SessionDelegate : public BaseDelegate
|
class SessionDelegate : public BaseDelegate
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
bool expanded(const QModelIndex &idx) const
|
||||||
|
{
|
||||||
|
return m_expandedSessions.contains(idx.data(Qt::DisplayRole).toString());
|
||||||
|
}
|
||||||
|
|
||||||
QString entryType() override
|
QString entryType() override
|
||||||
{
|
{
|
||||||
return Tr::tr("session", "Appears in \"Open session <name>\"");
|
return Tr::tr("session", "Appears in \"Open session <name>\"");
|
||||||
@@ -252,150 +294,287 @@ protected:
|
|||||||
{
|
{
|
||||||
// in expanded state bottom contains 'Clone', 'Rename', etc links, where the tool tip
|
// in expanded state bottom contains 'Clone', 'Rename', etc links, where the tool tip
|
||||||
// would be confusing
|
// would be confusing
|
||||||
const bool expanded = m_expandedSessions.contains(idx.data(Qt::DisplayRole).toString());
|
return expanded(idx) ? itemRect.adjusted(0, 0, 0, -actionButtonHeight()) : itemRect;
|
||||||
return expanded ? itemRect.adjusted(0, 0, 0, -LINK_HEIGHT) : itemRect;
|
}
|
||||||
|
|
||||||
|
int shortcutRole() const override
|
||||||
|
{
|
||||||
|
return SessionModel::ShortcutRole;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int actionButtonHeight()
|
||||||
|
{
|
||||||
|
return s(VPaddingXxs) + actionTF.lineHeight() + s(VPaddingXxs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const QPixmap &icon()
|
||||||
|
{
|
||||||
|
static const QPixmap icon = pixmap("session", Theme::Token_Text_Muted);
|
||||||
|
return icon;
|
||||||
}
|
}
|
||||||
int shortcutRole() const override { return SessionModel::ShortcutRole; }
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &idx) const final
|
void paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||||
|
const QModelIndex &idx) const final
|
||||||
{
|
{
|
||||||
static const QPixmap sessionIcon = pixmap("session", Theme::Welcome_ForegroundSecondaryColor);
|
// visible on withIcon() Gap + arrow visible on hover Extra margin right of project item
|
||||||
|
// | | |
|
||||||
const QRect rc = option.rect;
|
// +----------+----------+ +--------+-------+ +----------+----------+
|
||||||
const QString sessionName = idx.data(Qt::DisplayRole).toString();
|
// | | | | | |
|
||||||
|
//
|
||||||
|
// +------------+--------+--------+------------+--------+-------------+--------+-------+------------+---------------------+ --+
|
||||||
|
// | | | |(VPaddingXs)| |(VPaddingXs) | | | | | |
|
||||||
|
// | | | +------------+ +-------------+ | | | | |
|
||||||
|
// |(HPaddingXs)|<number>|(HGapXs)| <icon> |(HGapXs)|<sessionName>|(HGapXs)|<arrow>| | | +-- Header
|
||||||
|
// | |(16x16) | +------------+ +-------------+ | | | | |
|
||||||
|
// | | | |(VPaddingXs)| |(VPaddingXs) | | | | | |
|
||||||
|
// |------------+--------+--------+------------+--------+-------------+--------+-------+ | | --+
|
||||||
|
// | +-- | (VPaddingXs) | | | |
|
||||||
|
// | | +------------------------------+(HPaddingXs)| | |
|
||||||
|
// | | | <projectName> | | | |
|
||||||
|
// | | +------------------------------+ | | |
|
||||||
|
// | Per project in session --+ | (EXSPaddingGapS) | |(sessionScrollBarGap)| |
|
||||||
|
// | | +------------------------------+ | | |
|
||||||
|
// | | | <projectPath> | | | |
|
||||||
|
// | | +------------------------------+ | | +-- Expansion
|
||||||
|
// | +-- | (VPaddingXs) | | | |
|
||||||
|
// +----------------------------------------------+------------------------------------+------------+ | |
|
||||||
|
// | (VPaddingXs) | | |
|
||||||
|
// +----------------------------------------+--------------+----------------------------------------+ | |
|
||||||
|
// +-- | <cloneButton>|<renameButton>|<deleteButton> | | |
|
||||||
|
// | +----------------------------------------+--------------+----------------------------------------+ | |
|
||||||
|
// | | (VPaddingXs) | | |
|
||||||
|
// | +------------------------------------------------------------------------------------------------+---------------------+ --+
|
||||||
|
// | | (VGapL) | +-- Gap between session items
|
||||||
|
// | +----------------------------------------------------------------------------------------------------------------------+ --+
|
||||||
|
// |
|
||||||
|
// \ session action "buttons" and dividers
|
||||||
|
// +-----------------------------------------------+--------+---------+--------+
|
||||||
|
// | (VGapXs) | | | |
|
||||||
|
// +----------------+-------------+----------------+ | | |
|
||||||
|
// |(EXSPaddingGapM)|<buttonLabel>|(EXSPaddingGapM)|(HGapXs)|<divider>|(HGapXs)|
|
||||||
|
// +----------------+-------------+----------------+ |(w:1) | |
|
||||||
|
// | (VGapXs) | | | |
|
||||||
|
// +-----------------------------------------------+--------+---------+--------+
|
||||||
|
//
|
||||||
|
// | |
|
||||||
|
// +-------------+-------------+
|
||||||
|
// |
|
||||||
|
// omitted after last button
|
||||||
|
|
||||||
const QPoint mousePos = option.widget->mapFromGlobal(QCursor::pos());
|
const QPoint mousePos = option.widget->mapFromGlobal(QCursor::pos());
|
||||||
//const bool hovered = option.state & QStyle::State_MouseOver;
|
|
||||||
const bool hovered = option.rect.contains(mousePos);
|
const bool hovered = option.rect.contains(mousePos);
|
||||||
const bool expanded = m_expandedSessions.contains(sessionName);
|
const bool expanded = this->expanded(idx);
|
||||||
painter->fillRect(rc, themeColor(Theme::Welcome_BackgroundSecondaryColor));
|
|
||||||
painter->fillRect(rc.adjusted(0, 0, 0, -ItemGap),
|
|
||||||
hovered ? hoverColor : backgroundPrimaryColor);
|
|
||||||
|
|
||||||
const int x = rc.x();
|
const QRect bgR = option.rect.adjusted(0, 0, -sessionScrollBarGap, -itemSpacing());
|
||||||
const int x1 = x + TEXT_OFFSET_HORIZONTAL;
|
const QRect hdR(bgR.topLeft(), QSize(bgR.width(), expanded ? headerHeight()
|
||||||
const int y = rc.y();
|
: bgR.height()));
|
||||||
const int firstBase = y + 18;
|
|
||||||
|
|
||||||
painter->drawPixmap(x + 11, y + 6, sessionIcon);
|
const QSize iconS = icon().deviceIndependentSize().toSize();
|
||||||
|
static const QPixmap arrow = Icon({{FilePath::fromString(":/core/images/expandarrow"),
|
||||||
|
Theme::Token_Text_Muted}}, Icon::Tint).pixmap();
|
||||||
|
const QSize arrowS = arrow.deviceIndependentSize().toSize();
|
||||||
|
const bool arrowVisible = hovered || expanded;
|
||||||
|
|
||||||
if (hovered && !expanded) {
|
const QString sessionName = idx.data(Qt::DisplayRole).toString();
|
||||||
const QRect arrowRect = rc.adjusted(rc.width() - SESSION_ARROW_RECT_WIDTH, 0, 0, 0);
|
|
||||||
const bool arrowRectHovered = arrowRect.contains(mousePos);
|
const int x = bgR.x();
|
||||||
painter->fillRect(arrowRect.adjusted(0, 0, 0, -ItemGap),
|
const int y = bgR.y();
|
||||||
arrowRectHovered ? hoverColor : backgroundPrimaryColor);
|
|
||||||
|
const int numberX = x + s(HPaddingXs);
|
||||||
|
const int iconX = numberX + shortcutNumberWidth + s(HGapXs);
|
||||||
|
const int arrowX = bgR.right() - s(HPaddingXs) - arrowS.width();
|
||||||
|
const QRect arrowHoverR(arrowX - s(HGapXs) + 1, y,
|
||||||
|
s(HGapXs) + arrowS.width() + s(HPaddingXs), hdR.height());
|
||||||
|
const int textX = withIcon() ? iconX + iconS.width() + s(HGapXs) : iconX;
|
||||||
|
|
||||||
|
const int iconY = y + (hdR.height() - iconS.height()) / 2;
|
||||||
|
const int arrowY = y + (hdR.height() - arrowS.height()) / 2;
|
||||||
|
|
||||||
|
{
|
||||||
|
drawBackgroundRect(painter, bgR, hovered);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hovered || expanded) {
|
|
||||||
static const QPixmap arrowUp = pixmap("expandarrow",Theme::Welcome_ForegroundSecondaryColor);
|
|
||||||
static const QPixmap arrowDown = QPixmap::fromImage(arrowUp.toImage().mirrored(false, true));
|
|
||||||
painter->drawPixmap(rc.right() - 19, y + 6, expanded ? arrowDown : arrowUp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idx.row() < 9) {
|
if (idx.row() < 9) {
|
||||||
painter->setPen(foregroundSecondaryColor);
|
painter->setPen(shortcutNumberTF.color());
|
||||||
painter->setFont(sizedFont(10, option.widget));
|
painter->setFont(shortcutNumberTF.font());
|
||||||
painter->drawText(x + 3, firstBase, QString::number(idx.row() + 1));
|
const QRect numberR(numberX, y, shortcutNumberWidth, hdR.height());
|
||||||
|
const QString numberString = QString::number(idx.row() + 1);
|
||||||
|
painter->drawText(numberR, shortcutNumberTF.drawTextFlags, numberString);
|
||||||
}
|
}
|
||||||
|
if (withIcon()) {
|
||||||
|
painter->drawPixmap(iconX, iconY, icon());
|
||||||
|
}
|
||||||
|
{
|
||||||
const bool isLastSession = idx.data(SessionModel::LastSessionRole).toBool();
|
const bool isLastSession = idx.data(SessionModel::LastSessionRole).toBool();
|
||||||
const bool isActiveSession = idx.data(SessionModel::ActiveSessionRole).toBool();
|
const bool isActiveSession = idx.data(SessionModel::ActiveSessionRole).toBool();
|
||||||
const bool isDefaultVirgin = SessionManager::isDefaultVirgin();
|
const bool isDefaultVirgin = SessionManager::isDefaultVirgin();
|
||||||
|
|
||||||
|
const int sessionNameWidth = hdR.right()
|
||||||
|
- (arrowVisible ? arrowHoverR.width(): s(HPaddingXs))
|
||||||
|
- textX;
|
||||||
|
const int sessionNameHeight = sessionNameTF.lineHeight();
|
||||||
|
const int sessionNameY = y + (hdR.height() - sessionNameHeight) / 2;
|
||||||
|
const QRect sessionNameR(textX, sessionNameY, sessionNameWidth, sessionNameHeight);
|
||||||
|
|
||||||
QString fullSessionName = sessionName;
|
QString fullSessionName = sessionName;
|
||||||
if (isLastSession && isDefaultVirgin)
|
if (isLastSession && isDefaultVirgin)
|
||||||
fullSessionName = Tr::tr("%1 (last session)").arg(fullSessionName);
|
fullSessionName = Tr::tr("%1 (last session)").arg(fullSessionName);
|
||||||
if (isActiveSession && !isDefaultVirgin)
|
if (isActiveSession && !isDefaultVirgin)
|
||||||
fullSessionName = Tr::tr("%1 (current session)").arg(fullSessionName);
|
fullSessionName = Tr::tr("%1 (current session)").arg(fullSessionName);
|
||||||
|
const QRect switchR(x, y, hdR.width() - arrowHoverR.width(),
|
||||||
const QRect switchRect = QRect(x, y, rc.width() - SESSION_ARROW_RECT_WIDTH, SESSION_LINE_HEIGHT);
|
hdR.height() + s(VGapL));
|
||||||
const bool switchActive = switchRect.contains(mousePos);
|
const bool switchActive = switchR.contains(mousePos);
|
||||||
const int textSpace = rc.width() - TEXT_OFFSET_HORIZONTAL - 6;
|
painter->setPen(sessionNameTF.color());
|
||||||
const int sessionNameTextSpace =
|
painter->setFont(sessionNameTF.font(switchActive));
|
||||||
textSpace -(hovered || expanded ? SESSION_ARROW_RECT_WIDTH : 0);
|
|
||||||
painter->setPen(linkColor);
|
|
||||||
painter->setFont(sizedFont(13, option.widget, switchActive));
|
|
||||||
const QString fullSessionNameElided = painter->fontMetrics().elidedText(
|
const QString fullSessionNameElided = painter->fontMetrics().elidedText(
|
||||||
fullSessionName, Qt::ElideRight, sessionNameTextSpace);
|
fullSessionName, Qt::ElideRight, sessionNameWidth);
|
||||||
painter->drawText(x1, firstBase, fullSessionNameElided);
|
painter->drawText(sessionNameR, sessionNameTF.drawTextFlags,
|
||||||
|
fullSessionNameElided);
|
||||||
if (switchActive)
|
if (switchActive)
|
||||||
m_activeSwitchToRect = switchRect;
|
m_activeSwitchToRect = switchR;
|
||||||
|
}
|
||||||
|
if (arrowVisible) {
|
||||||
|
if (arrowHoverR.adjusted(0, 0, 0, s(VGapL)).contains(mousePos)) {
|
||||||
|
m_activeExpandRect = arrowHoverR;
|
||||||
|
} else {
|
||||||
|
painter->save();
|
||||||
|
painter->setClipRect(arrowHoverR);
|
||||||
|
drawBackgroundRect(painter, bgR, false);
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
static const QPixmap arrowDown =
|
||||||
|
QPixmap::fromImage(arrow.toImage().mirrored(false, true));
|
||||||
|
painter->drawPixmap(arrowX, arrowY, expanded ? arrowDown : arrow);
|
||||||
|
}
|
||||||
|
|
||||||
|
int yy = hdR.bottom();
|
||||||
if (expanded) {
|
if (expanded) {
|
||||||
painter->setPen(textColor);
|
const QFont projectNameFont = sessionProjetNameTF.font();
|
||||||
painter->setFont(sizedFont(12, option.widget));
|
const QFontMetrics projectNameFm(projectNameFont);
|
||||||
const FilePaths projects = ProjectManager::projectsForSessionName(sessionName);
|
const int projectNameLineHeight = sessionProjetNameTF.lineHeight();
|
||||||
int yy = firstBase + SESSION_LINE_HEIGHT - 3;
|
const QFont projectPathFont = projectPathTF.font();
|
||||||
QFontMetrics fm(option.widget->font());
|
const QFontMetrics projectPathFm(projectPathFont);
|
||||||
for (const FilePath &projectPath : projects) {
|
const int projectPathLineHeight = projectPathTF.lineHeight();
|
||||||
// Project name.
|
const int textWidth = bgR.right() - s(HPaddingXs) - textX;
|
||||||
QString completeBase = projectPath.completeBaseName();
|
|
||||||
painter->setPen(textColor);
|
|
||||||
painter->drawText(x1, yy, fm.elidedText(completeBase, Qt::ElideMiddle, textSpace));
|
|
||||||
yy += 18;
|
|
||||||
|
|
||||||
// Project path.
|
const FilePaths projects = ProjectManager::projectsForSessionName(sessionName);
|
||||||
|
for (const FilePath &projectPath : projects) {
|
||||||
|
yy += s(VPaddingXs);
|
||||||
|
{
|
||||||
|
painter->setFont(projectNameFont);
|
||||||
|
painter->setPen(sessionProjetNameTF.color());
|
||||||
|
const QRect projectNameR(textX, yy, textWidth, projectNameLineHeight);
|
||||||
|
const QString projectNameElided =
|
||||||
|
projectNameFm.elidedText(projectPath.completeBaseName(), Qt::ElideMiddle,
|
||||||
|
textWidth);
|
||||||
|
painter->drawText(projectNameR, sessionProjetNameTF.drawTextFlags,
|
||||||
|
projectNameElided);
|
||||||
|
yy += projectNameLineHeight;
|
||||||
|
yy += s(ExPaddingGapS);
|
||||||
|
}
|
||||||
|
{
|
||||||
const QString displayPath =
|
const QString displayPath =
|
||||||
projectPath.osType() == OsTypeWindows ? projectPath.displayName()
|
projectPath.osType() == OsTypeWindows ? projectPath.displayName()
|
||||||
: projectPath.withTildeHomePath();
|
: projectPath.withTildeHomePath();
|
||||||
painter->setPen(foregroundPrimaryColor);
|
painter->setFont(projectPathFont);
|
||||||
painter->drawText(x1, yy, fm.elidedText(displayPath, Qt::ElideMiddle, textSpace));
|
painter->setPen(projectPathTF.color());
|
||||||
yy += 22;
|
const QRect projectPathR(textX, yy, textWidth, projectPathLineHeight);
|
||||||
|
const QString projectPathElided =
|
||||||
|
projectPathFm.elidedText(displayPath, Qt::ElideMiddle, textWidth);
|
||||||
|
painter->drawText(projectPathR, projectPathTF.drawTextFlags,
|
||||||
|
projectPathElided);
|
||||||
|
yy += projectPathLineHeight;
|
||||||
}
|
}
|
||||||
|
yy += s(VPaddingXs);
|
||||||
|
}
|
||||||
|
yy += s(VGapXs);
|
||||||
|
|
||||||
yy += 3;
|
|
||||||
int xx = x1;
|
|
||||||
const QStringList actions = {
|
const QStringList actions = {
|
||||||
Tr::tr("Clone"),
|
Tr::tr("Clone"),
|
||||||
Tr::tr("Rename"),
|
Tr::tr("Rename"),
|
||||||
Tr::tr("Delete")
|
Tr::tr("Delete"),
|
||||||
};
|
};
|
||||||
for (int i = 0; i < 3; ++i) {
|
|
||||||
|
const QFont actionFont = actionTF.font();
|
||||||
|
const QFontMetrics actionFm(actionTF.font());
|
||||||
|
|
||||||
|
const int gapWidth = s(HGapXs) + actionSepWidth + s(HGapXs);
|
||||||
|
int actionsTotalWidth = gapWidth * int(actions.count() - 1); // dividers
|
||||||
|
const auto textWidths = Utils::transform(actions, [&] (const QString &action) {
|
||||||
|
const int width = actionFm.horizontalAdvance(action);
|
||||||
|
actionsTotalWidth += s(ExPaddingGapM) + width + s(ExPaddingGapM);
|
||||||
|
return width;
|
||||||
|
});
|
||||||
|
|
||||||
|
const int buttonHeight = this->actionButtonHeight();
|
||||||
|
int xx = (bgR.width() - actionsTotalWidth) / 2;
|
||||||
|
for (int i = 0; i < actions.count(); ++i) {
|
||||||
const QString &action = actions.at(i);
|
const QString &action = actions.at(i);
|
||||||
const int ww = fm.horizontalAdvance(action);
|
const int ww = textWidths.at(i);
|
||||||
const int spacing = 7; // Between action link and separator line
|
const QRect actionR(xx, yy, s(ExPaddingGapM) + ww + s(ExPaddingGapM), buttonHeight);
|
||||||
const QRect actionRect =
|
const bool isDisabled = i > 0 && SessionManager::isDefaultSession(sessionName);
|
||||||
QRect(xx, yy - 10, ww, 15).adjusted(-spacing, -spacing, spacing, spacing);
|
const bool isActive = actionR.adjusted(-s(VPaddingXs), 0, s(VPaddingXs) + 1, 0)
|
||||||
const bool isForcedDisabled = (i != 0 && sessionName == "default");
|
.contains(mousePos) && !isDisabled;
|
||||||
const bool isActive = actionRect.contains(mousePos) && !isForcedDisabled;
|
if (isActive) {
|
||||||
painter->setPen(isForcedDisabled ? disabledLinkColor : linkColor);
|
WelcomePageHelpers::drawCardBackground(painter, actionR, Qt::transparent,
|
||||||
painter->setFont(sizedFont(12, option.widget, isActive));
|
themeColor(Theme::Token_Text_Muted));
|
||||||
painter->drawText(xx, yy, action);
|
m_activeActionRects[i] = actionR;
|
||||||
if (i < 2) {
|
|
||||||
xx += ww + 2 * spacing;
|
|
||||||
int pp = xx - spacing;
|
|
||||||
painter->setPen(textColor);
|
|
||||||
painter->drawLine(pp, yy - 10, pp, yy);
|
|
||||||
}
|
}
|
||||||
if (isActive)
|
painter->setFont(actionFont);
|
||||||
m_activeActionRects[i] = actionRect;
|
painter->setPen((isDisabled ? actionDisabledTF : actionTF).color());
|
||||||
|
const QRect actionTextR = actionR.adjusted(0, 0, 0, -1);
|
||||||
|
painter->drawText(actionTextR, actionTF.drawTextFlags, action);
|
||||||
|
xx += actionR.width();
|
||||||
|
if (i < actions.count() - 1) {
|
||||||
|
const QRect dividerR(xx + s(HGapXs), yy, actionSepWidth, buttonHeight);
|
||||||
|
painter->fillRect(dividerR, themeColor(Theme::Token_Text_Muted));
|
||||||
}
|
}
|
||||||
|
xx += gapWidth;
|
||||||
}
|
}
|
||||||
|
yy += buttonHeight;
|
||||||
|
yy += s(VGapXs);
|
||||||
|
}
|
||||||
|
QTC_CHECK(option.rect.bottom() == yy + itemSpacing());
|
||||||
|
}
|
||||||
|
|
||||||
|
static int headerHeight()
|
||||||
|
{
|
||||||
|
const int paddingsHeight = s(VPaddingXs + VPaddingXs);
|
||||||
|
const int heightForSessionName = sessionNameTF.lineHeight() + paddingsHeight;
|
||||||
|
const int heightForIcon =
|
||||||
|
withIcon() ? int(icon().deviceIndependentSize().height()) + paddingsHeight : 0;
|
||||||
|
return qMax(heightForSessionName, heightForIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &idx) const final
|
QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &idx) const final
|
||||||
{
|
{
|
||||||
int h = SESSION_LINE_HEIGHT;
|
int h = headerHeight();
|
||||||
QString sessionName = idx.data(Qt::DisplayRole).toString();
|
if (expanded(idx)) {
|
||||||
if (m_expandedSessions.contains(sessionName)) {
|
const QString sessionName = idx.data(Qt::DisplayRole).toString();
|
||||||
const FilePaths projects = ProjectManager::projectsForSessionName(sessionName);
|
const FilePaths projects = ProjectManager::projectsForSessionName(sessionName);
|
||||||
h += projects.size() * 40 + LINK_HEIGHT - 6;
|
const int projectEntryHeight =
|
||||||
|
s(VPaddingXs)
|
||||||
|
+ projectNameTF.lineHeight()
|
||||||
|
+ s(ExPaddingGapS)
|
||||||
|
+ projectPathTF.lineHeight()
|
||||||
|
+ s(VPaddingXs);
|
||||||
|
h += projects.size() * projectEntryHeight
|
||||||
|
+ s(VGapXs)
|
||||||
|
+ actionButtonHeight()
|
||||||
|
+ s(VGapXs);
|
||||||
}
|
}
|
||||||
return QSize(380, h + ItemGap);
|
return QSize(-1, h + itemSpacing());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool editorEvent(QEvent *ev, QAbstractItemModel *model,
|
bool editorEvent(QEvent *ev, QAbstractItemModel *model,
|
||||||
const QStyleOptionViewItem &option, const QModelIndex &idx) final
|
const QStyleOptionViewItem &, const QModelIndex &idx) final
|
||||||
{
|
{
|
||||||
if (ev->type() == QEvent::MouseButtonRelease) {
|
if (ev->type() == QEvent::MouseButtonRelease) {
|
||||||
const QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(ev);
|
const QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(ev);
|
||||||
const Qt::MouseButtons button = mouseEvent->button();
|
const Qt::MouseButtons button = mouseEvent->button();
|
||||||
const QPoint pos = static_cast<QMouseEvent *>(ev)->pos();
|
const QPoint pos = static_cast<QMouseEvent *>(ev)->pos();
|
||||||
const QRect rc(option.rect.right() - SESSION_ARROW_RECT_WIDTH, option.rect.top(),
|
|
||||||
SESSION_ARROW_RECT_WIDTH, SESSION_LINE_HEIGHT);
|
|
||||||
const QString sessionName = idx.data(Qt::DisplayRole).toString();
|
const QString sessionName = idx.data(Qt::DisplayRole).toString();
|
||||||
if (rc.contains(pos) || button == Qt::RightButton) {
|
if (m_activeExpandRect.contains(pos) || button == Qt::RightButton) {
|
||||||
// The expand/collapse "button".
|
// The expand/collapse "button".
|
||||||
if (m_expandedSessions.contains(sessionName))
|
if (m_expandedSessions.contains(sessionName))
|
||||||
m_expandedSessions.removeOne(sessionName);
|
m_expandedSessions.removeOne(sessionName);
|
||||||
@@ -421,23 +600,15 @@ public:
|
|||||||
}
|
}
|
||||||
if (ev->type() == QEvent::MouseMove) {
|
if (ev->type() == QEvent::MouseMove) {
|
||||||
emit model->layoutChanged({QPersistentModelIndex(idx)}); // Somewhat brutish.
|
emit model->layoutChanged({QPersistentModelIndex(idx)}); // Somewhat brutish.
|
||||||
//update(option.rect);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const QColor hoverColor = themeColor(Theme::Welcome_HoverColor);
|
|
||||||
const QColor textColor = themeColor(Theme::Welcome_TextColor);
|
|
||||||
const QColor linkColor = themeColor(Theme::Welcome_LinkColor);
|
|
||||||
const QColor disabledLinkColor = themeColor(Theme::Welcome_DisabledLinkColor);
|
|
||||||
const QColor backgroundPrimaryColor = themeColor(Theme::Welcome_BackgroundPrimaryColor);
|
|
||||||
const QColor foregroundPrimaryColor = themeColor(Theme::Welcome_ForegroundPrimaryColor);
|
|
||||||
const QColor foregroundSecondaryColor = themeColor(Theme::Welcome_ForegroundSecondaryColor);
|
|
||||||
|
|
||||||
QStringList m_expandedSessions;
|
QStringList m_expandedSessions;
|
||||||
|
|
||||||
|
mutable QRect m_activeExpandRect;
|
||||||
mutable QRect m_activeSwitchToRect;
|
mutable QRect m_activeSwitchToRect;
|
||||||
mutable QRect m_activeActionRects[3];
|
mutable QRect m_activeActionRects[3];
|
||||||
};
|
};
|
||||||
@@ -453,58 +624,89 @@ class ProjectDelegate : public BaseDelegate
|
|||||||
public:
|
public:
|
||||||
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &idx) const final
|
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &idx) const final
|
||||||
{
|
{
|
||||||
QRect rc = option.rect;
|
// visible on withIcon() Extra margin right of project item
|
||||||
|
// | |
|
||||||
|
// +-------+-------+ +------+-----+
|
||||||
|
// | | | |
|
||||||
|
//
|
||||||
|
// +------------+--------+--------+------+--------+-------------+------------+------------+
|
||||||
|
// | | | | | | (VPaddingXs)| | |
|
||||||
|
// | | | | | +-------------+ | |
|
||||||
|
// | | | | | |<projectName>| | |
|
||||||
|
// | | | | | +-------------+ | |
|
||||||
|
// |(HPaddingXs)|<number>|(HGapXs)|<icon>|(HGapXs)| (VGapXs) |(HPaddingXs)|(HPaddingXs)|
|
||||||
|
// | |(16x16) | | | +-------------+ | |
|
||||||
|
// | | | | | |<projectPath>| | |
|
||||||
|
// | | | | | +-------------+ | |
|
||||||
|
// | | | | | | (VPaddingXs)| | |
|
||||||
|
// +------------+--------+--------+------+--------+-------------+------------+------------+ --+
|
||||||
|
// | (VGapL) | +-- Gap between project items
|
||||||
|
// +--------------------------------------------------------------------------------------+ --+
|
||||||
|
|
||||||
const bool hovered = option.widget->isActiveWindow() && option.state & QStyle::State_MouseOver;
|
const bool hovered = option.widget->isActiveWindow()
|
||||||
const QRect bgRect = rc.adjusted(0, 0, -ItemGap, -ItemGap);
|
&& option.state & QStyle::State_MouseOver;
|
||||||
painter->fillRect(rc, themeColor(Theme::Welcome_BackgroundSecondaryColor));
|
|
||||||
painter->fillRect(bgRect, themeColor(hovered ? Theme::Welcome_HoverColor
|
|
||||||
: Theme::Welcome_BackgroundPrimaryColor));
|
|
||||||
|
|
||||||
const int x = rc.x();
|
const QRect bgR = option.rect.adjusted(0, 0, -s(HPaddingXs), -itemSpacing());
|
||||||
const int y = rc.y();
|
|
||||||
const int firstBase = y + 18;
|
|
||||||
const int secondBase = firstBase + 19;
|
|
||||||
|
|
||||||
static const QPixmap projectIcon =
|
static const QPixmap icon = pixmap("project", Theme::Token_Text_Muted);
|
||||||
pixmap("project", Theme::Welcome_ForegroundSecondaryColor);
|
const QSize iconS = icon.deviceIndependentSize().toSize();
|
||||||
painter->drawPixmap(x + 11, y + 6, projectIcon);
|
|
||||||
|
|
||||||
QString projectName = idx.data(Qt::DisplayRole).toString();
|
const int x = bgR.x();
|
||||||
FilePath projectPath = FilePath::fromVariant(idx.data(ProjectModel::FilePathRole));
|
const int numberX = x + s(HPaddingXs);
|
||||||
|
const int iconX = numberX + shortcutNumberWidth + s(HGapXs);
|
||||||
|
const int iconWidth = iconS.width();
|
||||||
|
const int textX = withIcon() ? iconX + iconWidth + s(HGapXs) : iconX;
|
||||||
|
const int textWidth = bgR.width() - s(HPaddingXs) - textX;
|
||||||
|
|
||||||
painter->setPen(themeColor(Theme::Welcome_ForegroundSecondaryColor));
|
const int y = bgR.y();
|
||||||
painter->setFont(sizedFont(10, option.widget));
|
const int iconHeight = iconS.height();
|
||||||
|
const int iconY = y + (bgR.height() - iconHeight) / 2;
|
||||||
|
const int projectNameY = y + s(VPaddingXs);
|
||||||
|
const QRect projectNameR(textX, projectNameY, textWidth, projectNameTF.lineHeight());
|
||||||
|
const int projectPathY = projectNameY + projectNameR.height() + s(VGapXs);
|
||||||
|
const QRect projectPathR(textX, projectPathY, textWidth, projectPathTF.lineHeight());
|
||||||
|
|
||||||
if (idx.row() < 9)
|
QTC_CHECK(option.rect.bottom() == projectPathR.bottom() + s(VPaddingXs) + itemSpacing());
|
||||||
painter->drawText(x + 3, firstBase, QString::number(idx.row() + 1));
|
|
||||||
|
|
||||||
const int textSpace = rc.width() - TEXT_OFFSET_HORIZONTAL - ItemGap - 6;
|
{
|
||||||
|
drawBackgroundRect(painter, bgR, hovered);
|
||||||
painter->setPen(themeColor(Theme::Welcome_LinkColor));
|
}
|
||||||
painter->setFont(sizedFont(13, option.widget, hovered));
|
if (idx.row() < 9) {
|
||||||
|
painter->setPen(shortcutNumberTF.color());
|
||||||
|
painter->setFont(shortcutNumberTF.font());
|
||||||
|
const QRect numberR(numberX, y, shortcutNumberWidth, bgR.height());
|
||||||
|
const QString numberString = QString::number(idx.row() + 1);
|
||||||
|
painter->drawText(numberR, shortcutNumberTF.drawTextFlags, numberString);
|
||||||
|
}
|
||||||
|
if (withIcon()) {
|
||||||
|
painter->drawPixmap(iconX, iconY, icon);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
painter->setPen(projectNameTF.color());
|
||||||
|
painter->setFont(projectNameTF.font(hovered));
|
||||||
|
const QString projectName = idx.data(Qt::DisplayRole).toString();
|
||||||
const QString projectNameElided =
|
const QString projectNameElided =
|
||||||
painter->fontMetrics().elidedText(projectName, Qt::ElideRight, textSpace);
|
painter->fontMetrics().elidedText(projectName, Qt::ElideRight, textWidth);
|
||||||
painter->drawText(x + TEXT_OFFSET_HORIZONTAL, firstBase, projectNameElided);
|
painter->drawText(projectNameR, projectNameTF.drawTextFlags, projectNameElided);
|
||||||
|
}
|
||||||
painter->setPen(themeColor(Theme::Welcome_ForegroundPrimaryColor));
|
{
|
||||||
painter->setFont(sizedFont(13, option.widget));
|
painter->setPen(projectPathTF.color());
|
||||||
|
painter->setFont(projectPathTF.font());
|
||||||
|
const FilePath projectPath =
|
||||||
|
FilePath::fromVariant(idx.data(ProjectModel::FilePathRole));
|
||||||
const QString displayPath =
|
const QString displayPath =
|
||||||
projectPath.osType() == OsTypeWindows ? projectPath.displayName()
|
projectPath.osType() == OsTypeWindows ? projectPath.displayName()
|
||||||
: projectPath.withTildeHomePath();
|
: projectPath.withTildeHomePath();
|
||||||
const QString displayPathElided =
|
const QString displayPathElided =
|
||||||
painter->fontMetrics().elidedText(displayPath, Qt::ElideMiddle, textSpace);
|
painter->fontMetrics().elidedText(displayPath, Qt::ElideMiddle, textWidth);
|
||||||
painter->drawText(x + TEXT_OFFSET_HORIZONTAL, secondBase, displayPathElided);
|
painter->drawText(projectPathR, projectPathTF.drawTextFlags, displayPathElided);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &idx) const final
|
QSize sizeHint([[maybe_unused]] const QStyleOptionViewItem &option,
|
||||||
|
[[maybe_unused]] const QModelIndex &idx) const override
|
||||||
{
|
{
|
||||||
QString projectName = idx.data(Qt::DisplayRole).toString();
|
return QSize(-1, itemHeight() + itemSpacing());
|
||||||
QString projectPath = idx.data(ProjectModel::FilePathRole).toString();
|
|
||||||
QFontMetrics fm(sizedFont(13, option.widget));
|
|
||||||
int width = std::max(fm.horizontalAdvance(projectName),
|
|
||||||
fm.horizontalAdvance(projectPath)) + TEXT_OFFSET_HORIZONTAL;
|
|
||||||
return QSize(width, 47 + ItemGap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool editorEvent(QEvent *ev, QAbstractItemModel *model,
|
bool editorEvent(QEvent *ev, QAbstractItemModel *model,
|
||||||
@@ -541,6 +743,18 @@ public:
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static int itemHeight()
|
||||||
|
{
|
||||||
|
const int height =
|
||||||
|
s(VPaddingXs)
|
||||||
|
+ projectNameTF.lineHeight()
|
||||||
|
+ s(VGapXs)
|
||||||
|
+ projectPathTF.lineHeight()
|
||||||
|
+ s(VPaddingXs);
|
||||||
|
return height;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class TreeView : public QTreeView
|
class TreeView : public QTreeView
|
||||||
@@ -559,10 +773,7 @@ public:
|
|||||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||||
setFocusPolicy(Qt::NoFocus);
|
setFocusPolicy(Qt::NoFocus);
|
||||||
|
setBackgroundColor(viewport(), Theme::Token_Background_Default);
|
||||||
QPalette pal;
|
|
||||||
pal.setColor(QPalette::Base, themeColor(Theme::Welcome_BackgroundSecondaryColor));
|
|
||||||
viewport()->setPalette(pal);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -577,54 +788,63 @@ public:
|
|||||||
if (!projectWelcomePage->m_projectModel)
|
if (!projectWelcomePage->m_projectModel)
|
||||||
projectWelcomePage->m_projectModel = new ProjectModel(this);
|
projectWelcomePage->m_projectModel = new ProjectModel(this);
|
||||||
|
|
||||||
auto manageSessionsButton = new WelcomePageButton(this);
|
using namespace Layouting;
|
||||||
manageSessionsButton->setText(Tr::tr("Manage..."));
|
|
||||||
manageSessionsButton->setWithAccentColor(true);
|
|
||||||
manageSessionsButton->setOnClicked([] { SessionManager::showSessionManager(); });
|
|
||||||
|
|
||||||
auto sessionsLabel = new QLabel(this);
|
|
||||||
sessionsLabel->setText(Tr::tr("Sessions"));
|
|
||||||
|
|
||||||
auto recentProjectsLabel = new QLabel(this);
|
|
||||||
recentProjectsLabel->setText(Tr::tr("Projects"));
|
|
||||||
|
|
||||||
|
auto sessions = new QWidget;
|
||||||
|
{
|
||||||
|
auto sessionsLabel = new Label(Tr::tr("Sessions"), Label::Primary);
|
||||||
|
auto manageSessionsButton = new Button(Tr::tr("Manage..."), Button::MediumSecondary);
|
||||||
auto sessionsList = new TreeView(this, "Sessions");
|
auto sessionsList = new TreeView(this, "Sessions");
|
||||||
sessionsList->setModel(projectWelcomePage->m_sessionModel);
|
sessionsList->setModel(projectWelcomePage->m_sessionModel);
|
||||||
sessionsList->header()->setSectionHidden(1, true); // The "last modified" column.
|
sessionsList->header()->setSectionHidden(1, true); // The "last modified" column.
|
||||||
sessionsList->setItemDelegate(&m_sessionDelegate);
|
sessionsList->setItemDelegate(&m_sessionDelegate);
|
||||||
sessionsList->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
sessionsList->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||||
|
QSizePolicy sessionsSp(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
sessionsSp.setHorizontalStretch(3);
|
||||||
|
sessions->setSizePolicy(sessionsSp);
|
||||||
|
Column {
|
||||||
|
Row {
|
||||||
|
sessionsLabel,
|
||||||
|
st,
|
||||||
|
manageSessionsButton,
|
||||||
|
customMargin({HPaddingS, 0, sessionScrollBarGap, 0}),
|
||||||
|
},
|
||||||
|
sessionsList,
|
||||||
|
spacing(ExPaddingGapL),
|
||||||
|
customMargin({ExVPaddingGapXl, ExVPaddingGapXl, 0, 0}),
|
||||||
|
}.attachTo(sessions);
|
||||||
|
connect(manageSessionsButton, &Button::clicked,
|
||||||
|
this, &SessionManager::showSessionManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto projects = new QWidget;
|
||||||
|
{
|
||||||
|
auto projectsLabel = new Label(Tr::tr("Projects"), Label::Primary);
|
||||||
auto projectsList = new TreeView(this, "Recent Projects");
|
auto projectsList = new TreeView(this, "Recent Projects");
|
||||||
projectsList->setUniformRowHeights(true);
|
projectsList->setUniformRowHeights(true);
|
||||||
projectsList->setModel(projectWelcomePage->m_projectModel);
|
projectsList->setModel(projectWelcomePage->m_projectModel);
|
||||||
projectsList->setItemDelegate(&m_projectDelegate);
|
projectsList->setItemDelegate(&m_projectDelegate);
|
||||||
projectsList->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
projectsList->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||||
|
QSizePolicy projectsSP(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
projectsSP.setHorizontalStretch(5);
|
||||||
|
projects->setSizePolicy(projectsSP);
|
||||||
|
Column {
|
||||||
|
Row {
|
||||||
|
projectsLabel,
|
||||||
|
customMargin({HPaddingS, 0, 0, 0}),
|
||||||
|
},
|
||||||
|
projectsList,
|
||||||
|
spacing(ExPaddingGapL),
|
||||||
|
customMargin({ExVPaddingGapXl - sessionScrollBarGap, ExVPaddingGapXl, 0, 0}),
|
||||||
|
}.attachTo(projects);
|
||||||
|
}
|
||||||
|
|
||||||
auto sessionHeader = panelBar(this);
|
Row {
|
||||||
auto hbox11 = new QHBoxLayout(sessionHeader);
|
sessions,
|
||||||
hbox11->setContentsMargins(12, 0, 0, 0);
|
projects,
|
||||||
hbox11->addWidget(sessionsLabel);
|
spacing(0),
|
||||||
hbox11->addStretch(1);
|
noMargin(),
|
||||||
hbox11->addWidget(manageSessionsButton);
|
}.attachTo(this);
|
||||||
|
|
||||||
auto projectsHeader = panelBar(this);
|
|
||||||
auto hbox21 = new QHBoxLayout(projectsHeader);
|
|
||||||
hbox21->setContentsMargins(hbox11->contentsMargins());
|
|
||||||
hbox21->addWidget(recentProjectsLabel);
|
|
||||||
|
|
||||||
auto grid = new QGridLayout(this);
|
|
||||||
grid->setContentsMargins(0, 0, 0, ItemGap);
|
|
||||||
grid->setHorizontalSpacing(0);
|
|
||||||
grid->setVerticalSpacing(ItemGap);
|
|
||||||
grid->addWidget(panelBar(this), 0, 0);
|
|
||||||
grid->addWidget(sessionHeader, 0, 1);
|
|
||||||
grid->addWidget(sessionsList, 1, 1);
|
|
||||||
grid->addWidget(panelBar(this), 0, 2);
|
|
||||||
grid->setColumnStretch(1, 9);
|
|
||||||
grid->setColumnMinimumWidth(1, 200);
|
|
||||||
grid->addWidget(projectsHeader, 0, 3);
|
|
||||||
grid->addWidget(projectsList, 1, 3);
|
|
||||||
grid->setColumnStretch(3, 20);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionDelegate m_sessionDelegate;
|
SessionDelegate m_sessionDelegate;
|
||||||
|
@@ -250,7 +250,7 @@ static QPixmap fetchPixmapAndUpdatePixmapCache(const QString &url)
|
|||||||
const int dpr = qApp->devicePixelRatio();
|
const int dpr = qApp->devicePixelRatio();
|
||||||
// boundedTo -> don't scale thumbnails up
|
// boundedTo -> don't scale thumbnails up
|
||||||
const QSize scaledSize =
|
const QSize scaledSize =
|
||||||
WelcomePageHelpers::GridItemImageSize.boundedTo(img.size()) * dpr;
|
WelcomePageHelpers::WelcomeThumbnailSize.boundedTo(img.size()) * dpr;
|
||||||
const QImage scaled = img.isNull() ? img
|
const QImage scaled = img.isNull() ? img
|
||||||
: img.scaled(scaledSize,
|
: img.scaled(scaledSize,
|
||||||
Qt::KeepAspectRatio,
|
Qt::KeepAspectRatio,
|
||||||
|
@@ -21,13 +21,13 @@
|
|||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
|
#include <utils/layoutbuilder.h>
|
||||||
#include <utils/pathchooser.h>
|
#include <utils/pathchooser.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/stylehelper.h>
|
#include <utils/stylehelper.h>
|
||||||
#include <utils/theme/theme.h>
|
#include <utils/theme/theme.h>
|
||||||
#include <utils/winutils.h>
|
#include <utils/winutils.h>
|
||||||
|
|
||||||
#include <QComboBox>
|
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
@@ -249,7 +249,8 @@ protected:
|
|||||||
painter->setFont(option.font);
|
painter->setFont(option.font);
|
||||||
painter->setCompositionMode(QPainter::CompositionMode_Difference);
|
painter->setCompositionMode(QPainter::CompositionMode_Difference);
|
||||||
painter->setPen(Qt::white);
|
painter->setPen(Qt::white);
|
||||||
painter->drawText(currentPixmapRect.translated(0, -WelcomePageHelpers::ItemGap),
|
painter->drawText(
|
||||||
|
currentPixmapRect.translated(0, -StyleHelper::SpacingTokens::VPaddingXxs),
|
||||||
exampleItem->videoLength, Qt::AlignBottom | Qt::AlignHCenter);
|
exampleItem->videoLength, Qt::AlignBottom | Qt::AlignHCenter);
|
||||||
painter->restore();
|
painter->restore();
|
||||||
static const QPixmap playOverlay =
|
static const QPixmap playOverlay =
|
||||||
@@ -274,29 +275,25 @@ public:
|
|||||||
{
|
{
|
||||||
m_exampleDelegate.setShowExamples(isExamples);
|
m_exampleDelegate.setShowExamples(isExamples);
|
||||||
|
|
||||||
auto searchBox = new SearchBox(this);
|
using namespace StyleHelper::SpacingTokens;
|
||||||
m_searcher = searchBox->m_lineEdit;
|
|
||||||
|
|
||||||
auto grid = new QGridLayout(this);
|
using namespace Layouting;
|
||||||
grid->setContentsMargins(0, 0, 0, WelcomePageHelpers::ItemGap);
|
Row titleRow {
|
||||||
grid->setHorizontalSpacing(0);
|
customMargin({0, 0, ExVPaddingGapXl, 0}),
|
||||||
grid->setVerticalSpacing(WelcomePageHelpers::ItemGap);
|
spacing(ExVPaddingGapXl),
|
||||||
|
};
|
||||||
|
|
||||||
auto searchBar = WelcomePageHelpers::panelBar(this);
|
m_searcher = new SearchBox;
|
||||||
auto hbox = new QHBoxLayout(searchBar);
|
|
||||||
hbox->setContentsMargins(0, 0, 0, 0);
|
|
||||||
if (m_isExamples) {
|
if (m_isExamples) {
|
||||||
m_searcher->setPlaceholderText(Tr::tr("Search in Examples..."));
|
m_searcher->setPlaceholderText(Tr::tr("Search in Examples..."));
|
||||||
|
|
||||||
auto exampleSetSelector = new QComboBox(this);
|
auto exampleSetSelector = new ComboBox;
|
||||||
QPalette pal = exampleSetSelector->palette();
|
exampleSetSelector->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||||
// for macOS dark mode
|
exampleSetSelector->setMinimumWidth(ListItemDelegate::itemSize().width()
|
||||||
pal.setColor(QPalette::Text, Utils::creatorTheme()->color(Theme::Welcome_TextColor));
|
- ExVPaddingGapXl);
|
||||||
exampleSetSelector->setPalette(pal);
|
|
||||||
exampleSetSelector->setMinimumWidth(Core::WelcomePageHelpers::GridItemWidth);
|
|
||||||
exampleSetSelector->setMaximumWidth(Core::WelcomePageHelpers::GridItemWidth);
|
|
||||||
exampleSetSelector->setModel(s_exampleSetModel);
|
exampleSetSelector->setModel(s_exampleSetModel);
|
||||||
exampleSetSelector->setCurrentIndex(s_exampleSetModel->selectedExampleSet());
|
exampleSetSelector->setCurrentIndex(s_exampleSetModel->selectedExampleSet());
|
||||||
|
titleRow.addItem(exampleSetSelector);
|
||||||
connect(exampleSetSelector,
|
connect(exampleSetSelector,
|
||||||
&QComboBox::activated,
|
&QComboBox::activated,
|
||||||
s_exampleSetModel,
|
s_exampleSetModel,
|
||||||
@@ -305,23 +302,23 @@ public:
|
|||||||
&ExampleSetModel::selectedExampleSetChanged,
|
&ExampleSetModel::selectedExampleSetChanged,
|
||||||
exampleSetSelector,
|
exampleSetSelector,
|
||||||
&QComboBox::setCurrentIndex);
|
&QComboBox::setCurrentIndex);
|
||||||
|
|
||||||
hbox->setSpacing(Core::WelcomePageHelpers::HSpacing);
|
|
||||||
hbox->addWidget(exampleSetSelector);
|
|
||||||
} else {
|
} else {
|
||||||
m_searcher->setPlaceholderText(Tr::tr("Search in Tutorials..."));
|
m_searcher->setPlaceholderText(Tr::tr("Search in Tutorials..."));
|
||||||
}
|
}
|
||||||
hbox->addWidget(searchBox);
|
titleRow.addItem(m_searcher);
|
||||||
grid->addWidget(WelcomePageHelpers::panelBar(this), 0, 0);
|
|
||||||
grid->addWidget(searchBar, 0, 1);
|
|
||||||
grid->addWidget(WelcomePageHelpers::panelBar(this), 0, 2);
|
|
||||||
|
|
||||||
auto gridView = new SectionedGridView(this);
|
auto gridView = new SectionedGridView;
|
||||||
m_viewController
|
m_viewController
|
||||||
= new ExamplesViewController(s_exampleSetModel, gridView, m_searcher, isExamples, this);
|
= new ExamplesViewController(s_exampleSetModel, gridView, m_searcher, isExamples, this);
|
||||||
|
|
||||||
gridView->setItemDelegate(&m_exampleDelegate);
|
gridView->setItemDelegate(&m_exampleDelegate);
|
||||||
grid->addWidget(gridView, 1, 1, 1, 2);
|
|
||||||
|
Column {
|
||||||
|
titleRow,
|
||||||
|
gridView,
|
||||||
|
spacing(ExVPaddingGapXl),
|
||||||
|
customMargin({ExVPaddingGapXl, ExVPaddingGapXl, 0, 0}),
|
||||||
|
}.attachTo(this);
|
||||||
|
|
||||||
connect(&m_exampleDelegate, &ExampleDelegate::tagClicked,
|
connect(&m_exampleDelegate, &ExampleDelegate::tagClicked,
|
||||||
this, &ExamplesPageWidget::onTagClicked);
|
this, &ExamplesPageWidget::onTagClicked);
|
||||||
|
Before Width: | Height: | Size: 106 B |
Before Width: | Height: | Size: 148 B |
BIN
src/plugins/welcome/images/link.png
Normal file
After Width: | Height: | Size: 186 B |
BIN
src/plugins/welcome/images/link@2x.png
Normal file
After Width: | Height: | Size: 236 B |
Before Width: | Height: | Size: 106 B After Width: | Height: | Size: 175 B |
Before Width: | Height: | Size: 112 B After Width: | Height: | Size: 225 B |
Before Width: | Height: | Size: 118 B After Width: | Height: | Size: 192 B |
Before Width: | Height: | Size: 161 B After Width: | Height: | Size: 255 B |
@@ -8,8 +8,8 @@
|
|||||||
<file>images/project@2x.png</file>
|
<file>images/project@2x.png</file>
|
||||||
<file>images/session.png</file>
|
<file>images/session.png</file>
|
||||||
<file>images/session@2x.png</file>
|
<file>images/session@2x.png</file>
|
||||||
<file>images/expandarrow.png</file>
|
|
||||||
<file>images/expandarrow@2x.png</file>
|
|
||||||
<file>images/border.png</file>
|
<file>images/border.png</file>
|
||||||
|
<file>images/link.png</file>
|
||||||
|
<file>images/link@2x.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
@@ -22,12 +22,14 @@
|
|||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/icon.h>
|
#include <utils/icon.h>
|
||||||
|
#include <utils/layoutbuilder.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/styledbar.h>
|
#include <utils/styledbar.h>
|
||||||
#include <utils/stylehelper.h>
|
#include <utils/stylehelper.h>
|
||||||
#include <utils/theme/theme.h>
|
#include <utils/theme/theme.h>
|
||||||
#include <utils/treemodel.h>
|
#include <utils/treemodel.h>
|
||||||
|
|
||||||
|
#include <QButtonGroup>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
@@ -42,31 +44,15 @@ using namespace Core;
|
|||||||
using namespace Core::WelcomePageHelpers;
|
using namespace Core::WelcomePageHelpers;
|
||||||
using namespace ExtensionSystem;
|
using namespace ExtensionSystem;
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
using namespace StyleHelper::SpacingTokens;
|
||||||
|
|
||||||
namespace Welcome {
|
namespace Welcome {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class TopArea;
|
class TopArea;
|
||||||
class SideArea;
|
class SideArea;
|
||||||
class BottomArea;
|
|
||||||
|
|
||||||
const char currentPageSettingsKeyC[] = "Welcome2Tab";
|
const char currentPageSettingsKeyC[] = "Welcome2Tab";
|
||||||
constexpr int buttonSpacing = 16;
|
|
||||||
|
|
||||||
static QColor themeColor(Theme::Color role)
|
|
||||||
{
|
|
||||||
return Utils::creatorTheme()->color(role);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void addWeakVerticalSpacerToLayout(QVBoxLayout *layout, int maximumSize)
|
|
||||||
{
|
|
||||||
auto weakSpacer = new QWidget;
|
|
||||||
weakSpacer->setMaximumHeight(maximumSize);
|
|
||||||
weakSpacer->setMinimumHeight(buttonSpacing);
|
|
||||||
weakSpacer->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Maximum);
|
|
||||||
layout->addWidget(weakSpacer);
|
|
||||||
layout->setStretchFactor(weakSpacer, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
class WelcomeMode : public IMode
|
class WelcomeMode : public IMode
|
||||||
{
|
{
|
||||||
@@ -85,9 +71,9 @@ private:
|
|||||||
QStackedWidget *m_pageStack;
|
QStackedWidget *m_pageStack;
|
||||||
TopArea *m_topArea;
|
TopArea *m_topArea;
|
||||||
SideArea *m_sideArea;
|
SideArea *m_sideArea;
|
||||||
BottomArea *m_bottomArea;
|
|
||||||
QList<IWelcomePage *> m_pluginList;
|
QList<IWelcomePage *> m_pluginList;
|
||||||
QList<WelcomePageButton *> m_pageButtons;
|
QList<QPushButton *> m_pageButtons;
|
||||||
|
QButtonGroup *m_buttonGroup;
|
||||||
Id m_activePage;
|
Id m_activePage;
|
||||||
Id m_defaultPage;
|
Id m_defaultPage;
|
||||||
};
|
};
|
||||||
@@ -140,55 +126,43 @@ public:
|
|||||||
TopArea(QWidget *parent = nullptr)
|
TopArea(QWidget *parent = nullptr)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
setAutoFillBackground(true);
|
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
|
||||||
setMinimumHeight(11); // For compact state
|
|
||||||
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
|
||||||
setPalette(themeColor(Theme::Welcome_BackgroundPrimaryColor));
|
|
||||||
|
|
||||||
m_title = new QWidget;
|
constexpr TextFormat welcomeTF {Theme::Token_Text_Default, StyleHelper::UiElementH2};
|
||||||
|
|
||||||
auto hbox = new QHBoxLayout(m_title);
|
|
||||||
hbox->setSpacing(0);
|
|
||||||
hbox->setContentsMargins(HSpacing - 5, 2, 0, 2);
|
|
||||||
|
|
||||||
{
|
|
||||||
auto ideIconLabel = new QLabel;
|
auto ideIconLabel = new QLabel;
|
||||||
const QPixmap logo = Core::Icons::QTCREATORLOGO_BIG.pixmap();
|
|
||||||
ideIconLabel->setPixmap(logo.scaled(logo.size() * 0.6, Qt::IgnoreAspectRatio,
|
|
||||||
Qt::SmoothTransformation));
|
|
||||||
hbox->addWidget(ideIconLabel, 0);
|
|
||||||
|
|
||||||
hbox->addSpacing(16);
|
|
||||||
|
|
||||||
const QFont welcomeFont = StyleHelper::uiFont(StyleHelper::UiElementH1);
|
|
||||||
|
|
||||||
auto welcomeLabel = new QLabel("Welcome to");
|
|
||||||
welcomeLabel->setFont(welcomeFont);
|
|
||||||
hbox->addWidget(welcomeLabel, 0);
|
|
||||||
|
|
||||||
hbox->addSpacing(8);
|
|
||||||
|
|
||||||
auto ideNameLabel = new QLabel(QGuiApplication::applicationDisplayName());
|
|
||||||
ideNameLabel->setFont(welcomeFont);
|
|
||||||
ideNameLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
|
||||||
QPalette pal = palette();
|
|
||||||
pal.setColor(QPalette::WindowText, themeColor(Theme::Welcome_AccentColor));
|
|
||||||
ideNameLabel->setPalette(pal);
|
|
||||||
hbox->addWidget(ideNameLabel, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto mainLayout = new QHBoxLayout(this);
|
|
||||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
|
||||||
mainLayout->addWidget(m_title);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setCompact(bool compact)
|
|
||||||
{
|
{
|
||||||
m_title->setVisible(!compact);
|
const QPixmap logo = Core::Icons::QTCREATORLOGO_BIG.pixmap();
|
||||||
|
const int size = logo.width();
|
||||||
|
const QRect cropR = size == 128 ? QRect(9, 22, 110, 84) : QRect(17, 45, 222, 166);
|
||||||
|
const QPixmap croppedLogo = logo.copy(cropR);
|
||||||
|
const int lineHeight = welcomeTF.lineHeight();
|
||||||
|
const QPixmap scaledCroppedLogo =
|
||||||
|
croppedLogo.scaledToHeight((lineHeight - 12) * devicePixelRatioF(),
|
||||||
|
Qt::SmoothTransformation);
|
||||||
|
ideIconLabel->setPixmap(scaledCroppedLogo);
|
||||||
|
ideIconLabel->setFixedHeight(lineHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
auto welcomeLabel = new QLabel(Tr::tr("Welcome to %1")
|
||||||
QWidget *m_title;
|
.arg(QGuiApplication::applicationDisplayName()));
|
||||||
|
{
|
||||||
|
welcomeLabel->setFont(welcomeTF.font());
|
||||||
|
QPalette pal = palette();
|
||||||
|
pal.setColor(QPalette::WindowText, welcomeTF.color());
|
||||||
|
welcomeLabel->setPalette(pal);
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace Layouting;
|
||||||
|
|
||||||
|
Row {
|
||||||
|
ideIconLabel,
|
||||||
|
welcomeLabel,
|
||||||
|
st,
|
||||||
|
spacing(ExVPaddingGapXl),
|
||||||
|
customMargin({HPaddingM, VPaddingM, HPaddingM, VPaddingM}),
|
||||||
|
}.attachTo(this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SideArea : public QScrollArea
|
class SideArea : public QScrollArea
|
||||||
@@ -201,114 +175,103 @@ public:
|
|||||||
{
|
{
|
||||||
setWidgetResizable(true);
|
setWidgetResizable(true);
|
||||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
|
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
setFrameShape(QFrame::NoFrame);
|
setFrameShape(QFrame::NoFrame);
|
||||||
setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Ignored);
|
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored);
|
||||||
|
|
||||||
auto mainWidget = new QWidget(this);
|
using namespace Layouting;
|
||||||
mainWidget->setAutoFillBackground(true);
|
|
||||||
mainWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
|
||||||
mainWidget->setPalette(themeColor(Theme::Welcome_BackgroundPrimaryColor));
|
|
||||||
|
|
||||||
auto vbox = new QVBoxLayout(mainWidget);
|
Column mainLayout {
|
||||||
vbox->setSpacing(0);
|
spacing(0),
|
||||||
vbox->setContentsMargins(HSpacing, 0, HSpacing, 0);
|
customMargin({ExVPaddingGapXl, 0, ExVPaddingGapXl, 0}),
|
||||||
|
};
|
||||||
|
|
||||||
|
m_essentials = new QWidget;
|
||||||
|
Column essentials {
|
||||||
|
spacing(0),
|
||||||
|
noMargin(),
|
||||||
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
auto projectVBox = new QVBoxLayout;
|
auto newButton = new Button(Tr::tr("Create Project..."), Button::MediumPrimary);
|
||||||
projectVBox->setSpacing(buttonSpacing);
|
auto openButton = new Button(Tr::tr("Open Project..."), Button::MediumSecondary);
|
||||||
auto newButton = new WelcomePageButton(mainWidget);
|
|
||||||
newButton->setText(Tr::tr("Create Project..."));
|
|
||||||
newButton->setWithAccentColor(true);
|
|
||||||
newButton->setOnClicked([] {
|
|
||||||
QAction *openAction = ActionManager::command(Core::Constants::NEW)->action();
|
|
||||||
openAction->trigger();
|
|
||||||
});
|
|
||||||
|
|
||||||
auto openButton = new WelcomePageButton(mainWidget);
|
Column projectButtons {
|
||||||
openButton->setText(Tr::tr("Open Project..."));
|
newButton,
|
||||||
openButton->setWithAccentColor(true);
|
openButton,
|
||||||
openButton->setOnClicked([] {
|
spacing(ExPaddingGapL),
|
||||||
|
customMargin({0, ExVPaddingGapXl, 0, ExVPaddingGapXl}),
|
||||||
|
};
|
||||||
|
|
||||||
|
essentials.addItem(projectButtons);
|
||||||
|
|
||||||
|
connect(openButton, &Button::clicked, this, [] {
|
||||||
QAction *openAction = ActionManager::command(Core::Constants::OPEN)->action();
|
QAction *openAction = ActionManager::command(Core::Constants::OPEN)->action();
|
||||||
openAction->trigger();
|
openAction->trigger();
|
||||||
});
|
});
|
||||||
|
connect(newButton, &Button::clicked, this, [] {
|
||||||
projectVBox->addWidget(newButton);
|
QAction *openAction = ActionManager::command(Core::Constants::NEW)->action();
|
||||||
projectVBox->addWidget(openButton);
|
openAction->trigger();
|
||||||
vbox->addItem(projectVBox);
|
|
||||||
}
|
|
||||||
|
|
||||||
addWeakVerticalSpacerToLayout(vbox, 34);
|
|
||||||
|
|
||||||
{
|
|
||||||
auto newVBox = new QVBoxLayout;
|
|
||||||
newVBox->setSpacing(buttonSpacing / 3);
|
|
||||||
vbox->addItem(newVBox);
|
|
||||||
|
|
||||||
auto newLabel = new QLabel(Tr::tr("New to Qt?"), mainWidget);
|
|
||||||
newLabel->setAlignment(Qt::AlignHCenter);
|
|
||||||
newVBox->addWidget(newLabel);
|
|
||||||
|
|
||||||
auto getStartedButton = new WelcomePageButton(mainWidget);
|
|
||||||
getStartedButton->setText(Tr::tr("Get Started"));
|
|
||||||
getStartedButton->setOnClicked([] {
|
|
||||||
QDesktopServices::openUrl(
|
|
||||||
QString("qthelp://org.qt-project.qtcreator/doc/creator-getting-started.html"));
|
|
||||||
});
|
});
|
||||||
newVBox->addWidget(getStartedButton);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addWeakVerticalSpacerToLayout(vbox, 56);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
auto l = m_pluginButtons = new QVBoxLayout;
|
auto l = m_pluginButtons = new QVBoxLayout;
|
||||||
l->setSpacing(buttonSpacing);
|
l->setSpacing(VGapL);
|
||||||
vbox->addItem(l);
|
l->setContentsMargins({});
|
||||||
|
essentials.addItem(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
vbox->addStretch(1);
|
essentials.attachTo(m_essentials);
|
||||||
|
mainLayout.addItem(m_essentials);
|
||||||
|
mainLayout.addItem(st);
|
||||||
|
|
||||||
setWidget(mainWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
QVBoxLayout *m_pluginButtons = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
class BottomArea : public QWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
BottomArea(QWidget *parent = nullptr)
|
|
||||||
: QWidget(parent)
|
|
||||||
{
|
{
|
||||||
setAutoFillBackground(true);
|
auto label = new Label(Tr::tr("Explore more"), Label::Secondary);
|
||||||
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
label->setContentsMargins(HPaddingXxs, 0, 0, 0); // Is indented in Figma design
|
||||||
setPalette(themeColor(Theme::Welcome_BackgroundPrimaryColor));
|
|
||||||
|
|
||||||
auto hbox = new QHBoxLayout(this);
|
Column linksLayout {
|
||||||
hbox->setSpacing(0);
|
label,
|
||||||
hbox->setContentsMargins(0, 2 * ItemGap, HSpacing, 2 * ItemGap);
|
spacing(VGapS),
|
||||||
|
customMargin({0, VGapL, 0, ExVPaddingGapXl}),
|
||||||
|
};
|
||||||
|
|
||||||
const QList<QPair<QString, QString> > links {
|
const struct {
|
||||||
|
const QString label;
|
||||||
|
const QString url;
|
||||||
|
} links [] =
|
||||||
|
{
|
||||||
|
{ Tr::tr("Get Started"), "qthelp://org.qt-project.qtcreator/doc/creator-getting-started.html" },
|
||||||
{ Tr::tr("Get Qt"), "https://www.qt.io/download" },
|
{ Tr::tr("Get Qt"), "https://www.qt.io/download" },
|
||||||
{ Tr::tr("Qt Account"), "https://account.qt.io" },
|
{ Tr::tr("Qt Account"), "https://account.qt.io" },
|
||||||
{ Tr::tr("Online Community"), "https://forum.qt.io" },
|
{ Tr::tr("Online Community"), "https://forum.qt.io" },
|
||||||
{ Tr::tr("Blogs"), "https://planet.qt.io" },
|
{ Tr::tr("Blogs"), "https://planet.qt.io" },
|
||||||
{ Tr::tr("User Guide"), "qthelp://org.qt-project.qtcreator/doc/index.html" },
|
{ Tr::tr("User Guide"), "qthelp://org.qt-project.qtcreator/doc/index.html" },
|
||||||
};
|
};
|
||||||
for (const QPair<QString, QString> &link : links) {
|
for (auto &link : links) {
|
||||||
auto button = new WelcomePageButton(this);
|
auto button = new Button(link.label, Button::SmallLink, this);
|
||||||
button->setSize(WelcomePageButton::SizeSmall);
|
connect(button, &Button::clicked, this, [link]{
|
||||||
button->setText(link.first);
|
QDesktopServices::openUrl(link.url);});
|
||||||
button->setOnClicked([link]{ QDesktopServices::openUrl(link.second); });
|
button->setToolTip(link.url);
|
||||||
button->setWithAccentColor(true);
|
static const QPixmap icon = Icon({{":/welcome/images/link.png",
|
||||||
button->setMaximumWidth(220);
|
Theme::Token_Accent_Default}},
|
||||||
button->setToolTip(link.second);
|
Icon::Tint).pixmap();
|
||||||
if (hbox->count() > 0)
|
button->setPixmap(icon);
|
||||||
hbox->addStretch(1);
|
linksLayout.addItem(button);
|
||||||
hbox->addWidget(button, 20);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_links = new QWidget;
|
||||||
|
linksLayout.attachTo(m_links);
|
||||||
|
mainLayout.addItem(m_links);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QWidget *mainWidget = mainLayout.emerge();
|
||||||
|
setWidget(mainWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVBoxLayout *m_pluginButtons = nullptr;
|
||||||
|
QWidget *m_essentials = nullptr;
|
||||||
|
QWidget *m_links = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
WelcomeMode::WelcomeMode()
|
WelcomeMode::WelcomeMode()
|
||||||
@@ -327,41 +290,51 @@ WelcomeMode::WelcomeMode()
|
|||||||
setContextHelp("Qt Creator Manual");
|
setContextHelp("Qt Creator Manual");
|
||||||
setContext(Context(Constants::C_WELCOME_MODE));
|
setContext(Context(Constants::C_WELCOME_MODE));
|
||||||
|
|
||||||
QPalette palette = creatorTheme()->palette();
|
|
||||||
palette.setColor(QPalette::Window, themeColor(Theme::Welcome_BackgroundPrimaryColor));
|
|
||||||
|
|
||||||
m_modeWidget = new ResizeSignallingWidget;
|
m_modeWidget = new ResizeSignallingWidget;
|
||||||
m_modeWidget->setPalette(palette);
|
setBackgroundColor(m_modeWidget, Theme::Token_Background_Default);
|
||||||
connect(m_modeWidget, &ResizeSignallingWidget::resized, this,
|
connect(m_modeWidget, &ResizeSignallingWidget::resized, this,
|
||||||
[this](const QSize &size, const QSize &) {
|
[this](const QSize &size, const QSize &) {
|
||||||
const bool hideSideArea = size.width() <= 750;
|
const QSize essentialsS = m_sideArea->m_essentials->size();
|
||||||
const bool hideBottomArea = size.width() <= 850;
|
const QSize linksS = m_sideArea->m_links->size();
|
||||||
const bool compactVertically = size.height() <= 530;
|
const QSize sideAreaS = m_sideArea->size();
|
||||||
m_sideArea->setVisible(!hideSideArea);
|
const QSize topAreaS = m_topArea->size();
|
||||||
m_bottomArea->setVisible(!(hideBottomArea || compactVertically));
|
const QSize mainWindowS = ICore::mainWindow()->size();
|
||||||
m_topArea->setCompact(compactVertically);
|
|
||||||
|
const bool showSideArea = sideAreaS.width() < size.width() / 4;
|
||||||
|
const bool showTopArea = topAreaS.height() < mainWindowS.height() / 7.75;
|
||||||
|
const bool showLinks =
|
||||||
|
linksS.height() + essentialsS.height() < sideAreaS.height() && showTopArea;
|
||||||
|
|
||||||
|
m_sideArea->m_links->setVisible(showLinks);
|
||||||
|
m_sideArea->setVisible(showSideArea);
|
||||||
|
m_topArea->setVisible(showTopArea);
|
||||||
});
|
});
|
||||||
|
|
||||||
m_sideArea = new SideArea(m_modeWidget);
|
m_sideArea = new SideArea(m_modeWidget);
|
||||||
|
|
||||||
|
m_buttonGroup = new QButtonGroup(m_modeWidget);
|
||||||
|
m_buttonGroup->setExclusive(true);
|
||||||
|
|
||||||
m_pageStack = new QStackedWidget(m_modeWidget);
|
m_pageStack = new QStackedWidget(m_modeWidget);
|
||||||
palette.setColor(QPalette::Window, themeColor(Theme::Welcome_BackgroundSecondaryColor));
|
|
||||||
m_pageStack->setPalette(palette);
|
|
||||||
m_pageStack->setObjectName("WelcomeScreenStackedWidget");
|
m_pageStack->setObjectName("WelcomeScreenStackedWidget");
|
||||||
m_pageStack->setAutoFillBackground(true);
|
m_pageStack->setAutoFillBackground(true);
|
||||||
|
|
||||||
m_topArea = new TopArea;
|
m_topArea = new TopArea;
|
||||||
m_bottomArea = new BottomArea;
|
|
||||||
|
|
||||||
auto layout = new QGridLayout(m_modeWidget);
|
using namespace Layouting;
|
||||||
layout->addWidget(new StyledBar(m_modeWidget), 0, 0, 1, 2);
|
|
||||||
layout->addWidget(m_topArea, 1, 0, 1, 2);
|
Column {
|
||||||
layout->addWidget(m_sideArea, 2, 0, 2, 1);
|
new StyledBar,
|
||||||
layout->addWidget(m_pageStack, 2, 1, 1, 1);
|
m_topArea,
|
||||||
layout->setColumnStretch(1, 10);
|
createRule(Qt::Horizontal),
|
||||||
layout->addWidget(m_bottomArea, 3, 1, 1, 1);
|
Row {
|
||||||
layout->setContentsMargins(0, 0, 0, 0);
|
m_sideArea,
|
||||||
layout->setSpacing(0);
|
createRule(Qt::Vertical),
|
||||||
|
m_pageStack,
|
||||||
|
},
|
||||||
|
noMargin(),
|
||||||
|
spacing(0),
|
||||||
|
}.attachTo(m_modeWidget);
|
||||||
|
|
||||||
setWidget(m_modeWidget);
|
setWidget(m_modeWidget);
|
||||||
}
|
}
|
||||||
@@ -402,11 +375,11 @@ void WelcomeMode::addPage(IWelcomePage *page)
|
|||||||
if (m_pluginList.at(idx)->priority() >= pagePriority)
|
if (m_pluginList.at(idx)->priority() >= pagePriority)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
auto pageButton = new WelcomePageButton(m_sideArea->widget());
|
auto pageButton = new Button(page->title(), Button::SmallList, m_sideArea->widget());
|
||||||
auto pageId = page->id();
|
auto pageId = page->id();
|
||||||
pageButton->setText(page->title());
|
pageButton->setText(page->title());
|
||||||
pageButton->setActiveChecker([this, pageId] { return m_activePage == pageId; });
|
|
||||||
|
|
||||||
|
m_buttonGroup->addButton(pageButton);
|
||||||
m_pluginList.insert(idx, page);
|
m_pluginList.insert(idx, page);
|
||||||
m_pageButtons.insert(idx, pageButton);
|
m_pageButtons.insert(idx, pageButton);
|
||||||
|
|
||||||
@@ -417,6 +390,7 @@ void WelcomeMode::addPage(IWelcomePage *page)
|
|||||||
m_pageStack->insertWidget(idx, stackPage);
|
m_pageStack->insertWidget(idx, stackPage);
|
||||||
|
|
||||||
connect(page, &QObject::destroyed, this, [this, page, stackPage, pageButton] {
|
connect(page, &QObject::destroyed, this, [this, page, stackPage, pageButton] {
|
||||||
|
m_buttonGroup->removeButton(pageButton);
|
||||||
m_pluginList.removeOne(page);
|
m_pluginList.removeOne(page);
|
||||||
m_pageButtons.removeOne(pageButton);
|
m_pageButtons.removeOne(pageButton);
|
||||||
delete pageButton;
|
delete pageButton;
|
||||||
@@ -426,13 +400,13 @@ void WelcomeMode::addPage(IWelcomePage *page)
|
|||||||
auto onClicked = [this, pageId, stackPage] {
|
auto onClicked = [this, pageId, stackPage] {
|
||||||
m_activePage = pageId;
|
m_activePage = pageId;
|
||||||
m_pageStack->setCurrentWidget(stackPage);
|
m_pageStack->setCurrentWidget(stackPage);
|
||||||
for (WelcomePageButton *pageButton : std::as_const(m_pageButtons))
|
|
||||||
pageButton->recheckActive();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pageButton->setOnClicked(onClicked);
|
connect(pageButton, &Button::clicked, this, onClicked);
|
||||||
if (pageId == m_activePage)
|
if (pageId == m_activePage) {
|
||||||
onClicked();
|
onClicked();
|
||||||
|
pageButton->setChecked(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -664,6 +664,14 @@
|
|||||||
width="100%"
|
width="100%"
|
||||||
height="100%"
|
height="100%"
|
||||||
transform="matrix(1.5,0,0,1.5,0,-242)" />
|
transform="matrix(1.5,0,0,1.5,0,-242)" />
|
||||||
|
<use
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
xlink:href="#backgroundRect"
|
||||||
|
id="backgroundRect_18"
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
transform="matrix(1.125,0,0,1.125,0,-128.5)" />
|
||||||
<use
|
<use
|
||||||
x="0"
|
x="0"
|
||||||
y="0"
|
y="0"
|
||||||
@@ -7022,51 +7030,78 @@
|
|||||||
style="fill:none;stroke:#000000;stroke-width:1.42;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
style="fill:none;stroke:#000000;stroke-width:1.42;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
</g>
|
</g>
|
||||||
<g
|
<g
|
||||||
transform="translate(-202,374)"
|
transform="translate(-209,274)"
|
||||||
id="src/plugins/welcome/images/session">
|
id="src/plugins/welcome/images/session">
|
||||||
<rect
|
<use
|
||||||
id="rect4886-1-1"
|
x="0"
|
||||||
height="16"
|
y="0"
|
||||||
width="16"
|
xlink:href="#backgroundRect_24"
|
||||||
y="210"
|
id="use9"
|
||||||
x="250"
|
transform="translate(233,-210)" />
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1" />
|
|
||||||
<path
|
<path
|
||||||
id="path4942-1"
|
id="path8101"
|
||||||
d="m 252,212 v 12 h 12 v -12 z m 4,10 v -8 l 5,3.999 z"
|
style="fill:none;stroke:#000000;stroke-width:2;stroke-linejoin:round"
|
||||||
inkscape:connector-curvature="0"
|
d="m 219,210 6,4 -6,4 z m -7,-5 h 18 v 18 h -18 z" />
|
||||||
style="fill:#000000;fill-opacity:1" />
|
|
||||||
</g>
|
</g>
|
||||||
<g
|
<g
|
||||||
transform="translate(-86,374)"
|
transform="translate(19,478)"
|
||||||
id="src/plugins/welcome/images/expandarrow">
|
|
||||||
<rect
|
|
||||||
id="rect4961-9"
|
|
||||||
height="16"
|
|
||||||
width="16"
|
|
||||||
y="210"
|
|
||||||
x="150"
|
|
||||||
style="fill:#ffffff;fill-opacity:1" />
|
|
||||||
<polygon
|
|
||||||
id="polygon4959-0"
|
|
||||||
points="162,215 158,220 154,215 "
|
|
||||||
style="fill:#000000;fill-opacity:1"
|
|
||||||
transform="translate(0,1)" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
transform="translate(-220,374)"
|
|
||||||
id="src/plugins/welcome/images/project">
|
id="src/plugins/welcome/images/project">
|
||||||
<rect
|
<use
|
||||||
id="rect4950-8"
|
x="0"
|
||||||
height="16"
|
y="0"
|
||||||
width="16"
|
xlink:href="#backgroundRect_24"
|
||||||
y="210"
|
id="use9-5"
|
||||||
x="300"
|
transform="translate(30,-414)" />
|
||||||
style="fill:#ffffff;fill-opacity:1" />
|
<path
|
||||||
<polygon
|
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round"
|
||||||
id="polygon4948-6"
|
d="m 16,3 c 1,0 2,1 2,2 0,0 0,1 1,1 h 6 c 1,0 2,1 2,2 v 7 c 0,1 -1,2 -2,2 H 11 C 10,17 9,16 9,15 V 5 C 9,4 10,3 11,3 Z"
|
||||||
points="308,215 314,215 314,223 302,223 302,213 306,213 "
|
id="path2761-3"
|
||||||
style="fill:#000000;fill-opacity:1" />
|
sodipodi:nodetypes="cscccccccccc" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
transform="translate(44,478)"
|
||||||
|
id="src/plugins/welcome/images/link">
|
||||||
|
<use
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
xlink:href="#backgroundRect_24"
|
||||||
|
id="use14"
|
||||||
|
transform="translate(30,-414)"
|
||||||
|
width="100%"
|
||||||
|
height="100%" />
|
||||||
|
<path
|
||||||
|
id="path9"
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round"
|
||||||
|
d="m 22.5,5.5 -10,10 M 16,5 h 7 v 7" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
transform="translate(-81,276)"
|
||||||
|
id="src/plugins/coreplugin/images/expandarrow">
|
||||||
|
<use
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
xlink:href="#backgroundRect"
|
||||||
|
id="use15-0"
|
||||||
|
transform="translate(172,-228)" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
|
||||||
|
d="m 159,214.5 5,5 5,-5"
|
||||||
|
id="path2687"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
transform="translate(86,478)"
|
||||||
|
id="src/plugins/coreplugin/images/search">
|
||||||
|
<use
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
xlink:href="#backgroundRect"
|
||||||
|
id="use15"
|
||||||
|
transform="translate(22,-430)" />
|
||||||
|
<path
|
||||||
|
id="path10"
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:1.5;stroke-linecap:round"
|
||||||
|
d="m 17,17 3.5,3.5 m -2.25,-7 A 4.75,4.75 0 0 1 13.5,18.25 4.75,4.75 0 0 1 8.75,13.5 4.75,4.75 0 0 1 13.5,8.75 4.75,4.75 0 0 1 18.25,13.5 Z" />
|
||||||
</g>
|
</g>
|
||||||
<g
|
<g
|
||||||
id="src/libs/utils/images/member"
|
id="src/libs/utils/images/member"
|
||||||
|
Before Width: | Height: | Size: 373 KiB After Width: | Height: | Size: 374 KiB |
@@ -25,10 +25,14 @@ int main(int argc, char *argv[])
|
|||||||
{ StyleHelper::UiElementH5, "H5" },
|
{ StyleHelper::UiElementH5, "H5" },
|
||||||
{ StyleHelper::UiElementH6, "H6" },
|
{ StyleHelper::UiElementH6, "H6" },
|
||||||
{ StyleHelper::UiElementH6Capital, "H6 CAPITAL" },
|
{ StyleHelper::UiElementH6Capital, "H6 CAPITAL" },
|
||||||
|
{ StyleHelper::UiElementBody1, "Body-01" },
|
||||||
|
{ StyleHelper::UiElementBody2, "Body-02" },
|
||||||
|
{ StyleHelper::UiElementButtonMedium, "Button Medium" },
|
||||||
|
{ StyleHelper::UiElementButtonSmall, "Button Small" },
|
||||||
{ StyleHelper::UiElementCaptionStrong, "Caption strong" },
|
{ StyleHelper::UiElementCaptionStrong, "Caption strong" },
|
||||||
{ StyleHelper::UiElementCaption, "Caption" },
|
{ StyleHelper::UiElementCaption, "Caption" },
|
||||||
{ StyleHelper::UIElementIconStandard, "Icon Standard" },
|
{ StyleHelper::UiElementIconStandard, "Icon Standard" },
|
||||||
{ StyleHelper::UIElementIconActive, "Icon Active" },
|
{ StyleHelper::UiElementIconActive, "Icon Active" },
|
||||||
};
|
};
|
||||||
static const QString textSample("AaBbCcXxYyZz123");
|
static const QString textSample("AaBbCcXxYyZz123");
|
||||||
|
|
||||||
|