Skip to content

Commit 6f72d16

Browse files
committed
Add Dark Mode support for Windows
1 parent f0199f3 commit 6f72d16

File tree

9 files changed

+157
-86
lines changed

9 files changed

+157
-86
lines changed

clientgui/BOINCGUIApp.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@ bool CBOINCGUIApp::OnInit() {
108108
#if SUPPORTDARKMODE
109109
wxSystemAppearance appearance = wxSystemSettings::GetAppearance();
110110
m_isDarkMode = appearance.IsDark();
111+
#if defined(__WXMSW__)
112+
// wxWidgets' IsDark() returns false on Win 11 now even if dark mode is enabled
113+
// so we need to additionally check AreAppsDark()
114+
m_isDarkMode = m_isDarkMode || appearance.AreAppsDark();
115+
MSWEnableDarkMode(wxApp::DarkMode_Auto);
116+
#endif
111117
#endif
112118

113119
s_bSkipExitConfirmation = false;

clientgui/BOINCGUIApp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
// BOINC to adjust standard UI items for Dark Mode, be sure to guard
4242
// those changes so they do not affect the Mac implementation.
4343
//
44-
#if (defined(__WXMAC__) || defined(__WXGTK__))
44+
#if (defined(__WXMAC__) || defined(__WXGTK__) || defined(__WXMSW__))
4545
#define SUPPORTDARKMODE true
4646
#else
4747
#define SUPPORTDARKMODE false

clientgui/BOINCListCtrl.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -524,8 +524,23 @@ void CBOINCListCtrl::DrawProgressBars()
524524
int n = (int)m_iRowsNeedingProgressBars.GetCount();
525525
if (n <= 0) return;
526526

527-
wxColour progressColor = isDarkMode ? wxColour(0, 64, 128) : wxColour(192, 217, 217);
527+
wxColour progressColor;
528+
wxColour remainderColor;
529+
wxColour textColor;
530+
531+
if (isDarkMode) {
532+
progressColor = wxColour(96, 96, 96);
533+
remainderColor = wxColour(24, 24, 24);
534+
textColor = wxColour(230, 230, 230);
535+
} else {
536+
progressColor = wxColour(192, 217, 217);
537+
remainderColor = *wxWHITE;
538+
textColor = *wxBLACK;
539+
}
540+
528541
wxBrush progressBrush(progressColor);
542+
wxBrush remainderBrush(remainderColor);
543+
wxPen remainderPen(remainderColor);
529544

530545
numItems = GetItemCount();
531546
if (numItems) {
@@ -606,12 +621,13 @@ void CBOINCListCtrl::DrawProgressBars()
606621
dc.SetPen(bkgd);
607622
dc.SetBrush(bkgd);
608623
#else
609-
dc.SetPen(isDarkMode ? *wxBLACK_PEN : *wxWHITE_PEN);
610-
dc.SetBrush(isDarkMode ? *wxBLACK_BRUSH : *wxWHITE_BRUSH);
624+
dc.SetPen(remainderPen);
625+
dc.SetBrush(remainderBrush);
611626
#endif
612627
dc.DrawRectangle( rr );
613628

614629
dc.SetPen(*wxBLACK_PEN);
630+
dc.SetTextForeground(textColor);
615631
dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
616632
if (xx > (r.width - 7)) {
617633
dc.DrawText(progressString, r.x, r.y);

clientgui/NoticeListCtrl.cpp

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,43 @@
3434
#include "MainDocument.h"
3535
#include "NoticeListCtrl.h"
3636

37+
#if wxUSE_WEBVIEW
38+
wxString BuildNoticeHtmlStart(bool darkMode) {
39+
const wxString style = darkMode ?
40+
wxT("<style>"
41+
"body { background-color:#000000; color:#f2f2f2; font-family:Helvetica,Arial,sans-serif; }"
42+
"a { color:#4fb3ff !important; }"
43+
"hr { border:0; border-top:1px solid #303030; }"
44+
".notice-footer { color:#a0a0a0 !important; font-size:0.8em; }"
45+
"</style>")
46+
:
47+
wxT("<style>"
48+
"body { background-color:#ffffff; color:#000000; font-family:Helvetica,Arial,sans-serif; }"
49+
"a { color:#0645ad; }"
50+
"hr { border:0; border-top:1px solid #dcdcdc; }"
51+
".notice-footer { color:#6f6f6f; font-size:0.8em; }"
52+
"</style>");
53+
return wxT("<html><head>") + style + wxT("</head><body>");
54+
}
55+
#else
56+
wxString BuildNoticeHtmlStart(bool darkMode) {
57+
const wxString linkColour = darkMode ? wxT("#4fb3ff") : wxT("#0645ad");
58+
const wxString ruleColour = darkMode ? wxT("#303030") : wxT("#dcdcdc");
59+
const wxString footerColour = darkMode ? wxT("#a0a0a0") : wxT("#6f6f6f");
60+
const wxString bodyAttrs = darkMode
61+
? wxT(" bgcolor=\"#000000\" text=\"#f2f2f2\"")
62+
: wxT(" bgcolor=\"#ffffff\" text=\"#000000\"");
63+
const wxString style =
64+
wxT("<style type=\"text/css\">")
65+
wxT("body { font-family:Helvetica,Arial,sans-serif; }")
66+
wxT("a { color:") + linkColour + wxT("; }")
67+
wxT("hr { border:0; border-top:1px solid ") + ruleColour + wxT("; }")
68+
wxT(".notice-footer { color:") + footerColour + wxT("; font-size:0.8em; }")
69+
wxT("</style>");
70+
return wxT("<html><head>") + style + wxT("</head><body") + bodyAttrs + wxT(">");
71+
}
72+
#endif // wxUSE_WEBVIEW
73+
3774
////@begin XPM images
3875
////@end XPM images
3976

@@ -101,20 +138,9 @@ bool CNoticeListCtrl::Create( wxWindow* parent ) {
101138
SetSizer(topsizer);
102139

103140
m_itemCount = 0;
104-
bool isWindowsDarkMode = false;
105-
#ifdef __WXMSW__
106-
const wxSystemAppearance appearance = wxSystemSettings::GetAppearance();
107-
isWindowsDarkMode = appearance.IsSystemDark();
108-
#endif
109-
if (wxGetApp().GetIsDarkMode() || isWindowsDarkMode){
110-
#if wxUSE_WEBVIEW
111-
m_noticesBody = wxT("<html><style>body{background-color:black;color:white;}</style><head></head><body></body></html>");
112-
#else
113-
m_noticesBody = wxT("<html><head></head><body bgcolor=black></body></html>");
114-
#endif
115-
} else {
116-
m_noticesBody = wxT("<html><head></head><body></body></html>");
117-
}
141+
142+
const bool darkMode = wxGetApp().GetIsDarkMode();
143+
m_noticesBody = BuildNoticeHtmlStart(darkMode) + wxT("</body></html>");
118144

119145
// In Dark Mode, paint the window black immediately
120146
#if wxUSE_WEBVIEW
@@ -158,21 +184,8 @@ void CNoticeListCtrl::SetItemCount(int newCount) {
158184
wxASSERT(pSkinAdvanced);
159185
wxASSERT(wxDynamicCast(pSkinAdvanced, CSkinAdvanced));
160186

161-
m_itemCount = newCount;
162-
bool isWindowsDarkMode = false;
163-
#ifdef __WXMSW__
164-
const wxSystemAppearance appearance = wxSystemSettings::GetAppearance();
165-
isWindowsDarkMode = appearance.IsSystemDark();
166-
#endif
167-
if (wxGetApp().GetIsDarkMode() || isWindowsDarkMode){
168-
#if wxUSE_WEBVIEW
169-
m_noticesBody = wxT("<html><style>body{background-color:black;color:white;}</style><head></head><body><font face=helvetica>");
170-
#else
171-
m_noticesBody = wxT("<html><head></head><body bgcolor=black><font face=helvetica color=white bgcolor=black>");
172-
#endif
173-
} else {
174-
m_noticesBody = wxT("<html><head></head><body><font face=helvetica>");
175-
}
187+
const bool darkMode = wxGetApp().GetIsDarkMode();
188+
m_noticesBody = BuildNoticeHtmlStart(darkMode);
176189

177190
for (i=0; i<newCount; ++i) {
178191
if (pDoc->IsConnected()) {
@@ -245,7 +258,7 @@ void CNoticeListCtrl::SetItemCount(int newCount) {
245258
strBuffer = wxT("<hr>");
246259
}
247260

248-
strBuffer += wxT("<table border=0 cellpadding=5><tr><td>");
261+
strBuffer += wxT("<table class=\"notice\" border=0 cellpadding=5 cellspacing=0><tr><td>");
249262

250263
if (!strTitle.IsEmpty()) {
251264
strTemp.Printf(
@@ -257,7 +270,7 @@ void CNoticeListCtrl::SetItemCount(int newCount) {
257270

258271
strBuffer += strDescription;
259272

260-
strBuffer += wxT("<br><font size=-2 color=#8f8f8f>");
273+
strBuffer += wxT("<div class=\"notice-footer\">");
261274

262275
strBuffer += strCreateTime;
263276

@@ -270,11 +283,11 @@ void CNoticeListCtrl::SetItemCount(int newCount) {
270283
strBuffer += strTemp;
271284
}
272285

273-
strBuffer += wxT("</font></td></tr></table>");
286+
strBuffer += wxT("</div></td></tr></table>");
274287
}
275288
m_noticesBody += strBuffer;
276289
}
277-
m_noticesBody += wxT("</font></body></html>");
290+
m_noticesBody += wxT("</body></html>");
278291
// baseURL is not needed here (see comments above) and it
279292
// must be an empty string for this to work under OS 10.12.4
280293
#if wxUSE_WEBVIEW

clientgui/ViewResources.cpp

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,26 +40,28 @@ END_EVENT_TABLE ()
4040

4141

4242
CViewResources::CViewResources()
43+
: m_BOINCwasEmpty(false)
44+
, m_isDarkTheme(wxGetApp().GetIsDarkMode())
4345
{}
4446

4547
CViewResources::CViewResources(wxNotebook* pNotebook) :
4648
CBOINCBaseView(pNotebook)
49+
, m_BOINCwasEmpty(false)
50+
, m_isDarkTheme(wxGetApp().GetIsDarkMode())
4751
{
48-
bool isDarkMode = wxGetApp().GetIsDarkMode();
49-
m_BOINCwasEmpty=false;
50-
5152
wxGridSizer* itemGridSizer = new wxGridSizer(2, 0, 3);
5253
wxASSERT(itemGridSizer);
5354

5455
// create pie chart ctrl for total disk usage
5556
m_pieCtrlTotal = new wxPieCtrl(this, ID_PIECTRL_RESOURCEUTILIZATIONVIEWTOTAL, wxDefaultPosition, wxDefaultSize);
5657
wxASSERT(m_pieCtrlTotal);
58+
m_pieCtrlTotal->ApplyTheme(m_isDarkTheme);
5759

5860
// setup the legend
5961
m_pieCtrlTotal->SetTransparent(true);
6062
m_pieCtrlTotal->SetHorLegendBorder(10);
6163
m_pieCtrlTotal->SetLabelFont(*wxSWISS_FONT);
62-
m_pieCtrlTotal->SetLabelColour(isDarkMode ? *wxWHITE : *wxBLACK);
64+
m_pieCtrlTotal->SetLabelColour(m_isDarkTheme ? *wxWHITE : *wxBLACK);
6365
m_pieCtrlTotal->SetLabel(_("Total disk usage"));
6466

6567
// initialize pie control
@@ -75,12 +77,13 @@ CViewResources::CViewResources(wxNotebook* pNotebook) :
7577
// create pie chart ctrl for BOINC disk usage
7678
m_pieCtrlBOINC = new wxPieCtrl(this, ID_PIECTRL_RESOURCEUTILIZATIONVIEW, wxDefaultPosition, wxDefaultSize);
7779
wxASSERT(m_pieCtrlBOINC);
80+
m_pieCtrlBOINC->ApplyTheme(m_isDarkTheme);
7881

7982
//setup the legend
8083
m_pieCtrlBOINC->SetTransparent(true);
8184
m_pieCtrlBOINC->SetHorLegendBorder(10);
8285
m_pieCtrlBOINC->SetLabelFont(*wxSWISS_FONT);
83-
m_pieCtrlTotal->SetLabelColour(isDarkMode ? *wxWHITE : *wxBLACK);
86+
m_pieCtrlBOINC->SetLabelColour(m_isDarkTheme ? *wxWHITE : *wxBLACK);
8487
m_pieCtrlBOINC->SetLabel(_("Disk usage by BOINC projects"));
8588

8689
// initialize pie control
@@ -173,7 +176,6 @@ void CViewResources::OnListRender() {
173176
wxString diskspace;
174177
static double project_total=0.0;
175178
unsigned int i;
176-
bool isDarkMode = wxGetApp().GetIsDarkMode();
177179

178180
wxASSERT(pDoc);
179181
wxASSERT(wxDynamicCast(pDoc, CMainDocument));
@@ -228,7 +230,7 @@ void CViewResources::OnListRender() {
228230
wxPiePart part;
229231
part.SetLabel(_("no projects: 0 bytes used"));
230232
part.SetValue(1);
231-
part.SetColour(isDarkMode ? wxColour(255, 255, 255) : wxColour(0,0,0));
233+
part.SetColour(m_isDarkTheme ? wxColour(255, 255, 255) : wxColour(0,0,0));
232234
m_pieCtrlBOINC->m_Series.Add(part);
233235
m_pieCtrlBOINC->Refresh();
234236
m_BOINCwasEmpty=true;
@@ -263,8 +265,7 @@ void CViewResources::OnListRender() {
263265
FormatDiskSpace(boinc_total, diskspace);
264266
part.SetLabel(_("used by BOINC: ") + diskspace);
265267
part.SetValue(boinc_total);
266-
part.SetColour(isDarkMode ? wxColour(255, 255, 255) : wxColour(0,0,0));
267-
part.SetColour(isDarkMode ? *wxWHITE : *wxBLACK);
268+
part.SetColour(m_isDarkTheme ? *wxWHITE : *wxBLACK);
268269
m_pieCtrlTotal->m_Series.Add(part);
269270

270271
if (pDoc->disk_usage.d_allowed > 0) {
@@ -274,15 +275,15 @@ void CViewResources::OnListRender() {
274275
FormatDiskSpace(avail, diskspace);
275276
part.SetLabel(_("free, available to BOINC: ") + diskspace);
276277
part.SetValue(avail == 0 ? 1 : avail);
277-
part.SetColour(isDarkMode ? wxColour(108, 108, 108) : wxColour(128, 128, 128));
278+
part.SetColour(m_isDarkTheme ? wxColour(108, 108, 108) : wxColour(128, 128, 128));
278279
m_pieCtrlTotal->m_Series.Add(part);
279280

280281
double not_avail = free - avail;
281282
if (not_avail > 0) {
282283
FormatDiskSpace(not_avail, diskspace);
283284
part.SetLabel(_("free, not available to BOINC: ") + diskspace);
284285
part.SetValue(not_avail);
285-
part.SetColour(isDarkMode ? wxColour(172,172,172) : wxColour(238,238,238));
286+
part.SetColour(m_isDarkTheme ? wxColour(172,172,172) : wxColour(238,238,238));
286287
m_pieCtrlTotal->m_Series.Add(part);
287288
}
288289
} else {
@@ -292,7 +293,7 @@ void CViewResources::OnListRender() {
292293
FormatDiskSpace(free, diskspace);
293294
part.SetLabel(_("free: ") + diskspace);
294295
part.SetValue(free);
295-
part.SetColour(isDarkMode ? wxColour(172,172,172) : wxColour(238,238,238));
296+
part.SetColour(m_isDarkTheme ? wxColour(172,172,172) : wxColour(238,238,238));
296297
m_pieCtrlTotal->m_Series.Add(part);
297298
}
298299

@@ -301,7 +302,7 @@ void CViewResources::OnListRender() {
301302
FormatDiskSpace(used_by_others, diskspace);
302303
part.SetLabel(_("used by other programs: ") + diskspace);
303304
part.SetValue(used_by_others);
304-
part.SetColour(isDarkMode ? wxColour(140,140,140) : wxColour(192,192,192));
305+
part.SetColour(m_isDarkTheme ? wxColour(140,140,140) : wxColour(192,192,192));
305306
m_pieCtrlTotal->m_Series.Add(part);
306307
m_pieCtrlTotal->Refresh();
307308
}

clientgui/ViewResources.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class CViewResources : public CBOINCBaseView
5252
wxPieCtrl* m_pieCtrlTotal;
5353

5454
bool m_BOINCwasEmpty;
55+
bool m_isDarkTheme;
5556

5657
virtual void UpdateSelection();
5758

clientgui/ViewStatistics.cpp

Lines changed: 59 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -157,34 +157,65 @@ CPaintStatistics::CPaintStatistics(wxWindow* parent, wxWindowID id, const wxPoin
157157
m_LegendDraw = true;
158158

159159
// Default colours
160-
m_pen_MarkerLineColour = wxColour(0, 0, 0);
161-
m_pen_ZoomRectColour = wxColour (128, 64, 95);
162-
m_brush_ZoomRectColour = wxColour(24, 31, 0);
163-
m_brush_AxisColour = wxColour(192, 224, 255);
164-
m_pen_AxisColour = wxColour(64, 128, 192);
165-
m_pen_AxisColourZoom = wxColour(255, 64, 0);
166-
m_pen_AxisColourAutoZoom = wxColour(64, 128, 192);
167-
m_pen_AxisXColour = wxColour(64, 128, 192);
168-
m_pen_AxisYColour = wxColour(64, 128, 192);
169-
m_pen_AxisXTextColour = isDarkMode ? wxColour(255, 255, 255) : wxColour(0,0,0);
170-
m_pen_AxisYTextColour = isDarkMode ? wxColour(255, 255, 255) : wxColour(0,0,0);
171-
172-
m_brush_LegendColour = isDarkMode ? wxColour(0, 64, 128) : wxColour(235, 255, 255);
173-
m_brush_LegendSelectColour = wxColour(192, 224, 255);
174-
m_pen_LegendSelectColour = wxColour(64, 128, 192);
175-
m_pen_LegendSelectTextColour = isDarkMode ? wxColour(255, 255, 255) : wxColour(0,0,0);
176-
m_pen_LegendColour = wxColour(64, 128, 192);
177-
m_pen_LegendTextColour = isDarkMode ? wxColour(255, 255, 255) : wxColour(0,0,0);
178-
m_brush_MainColour = isDarkMode ? wxColour(0,0,0) : wxColour(255, 255, 255);
179-
m_pen_MainColour = wxColour(64, 128, 192);
180-
181-
m_pen_HeadTextColour = isDarkMode ? wxColour(255, 255, 255) : wxColour(0,0,0);
182-
m_pen_ProjectHeadTextColour = isDarkMode ? wxColour(255, 255, 255) : wxColour(0,0,0);
183-
184-
m_pen_GraphTotalColour = wxColour(255, 0, 0);
185-
m_pen_GraphRACColour = wxColour(0, 160, 0);
186-
m_pen_GraphTotalHostColour = wxColour(0, 0, 255);
187-
m_pen_GraphRACHostColour = wxColour(0, 0, 0);
160+
if (isDarkMode) {
161+
m_pen_MarkerLineColour = wxColour(220, 220, 220);
162+
m_pen_ZoomRectColour = wxColour(180, 200, 220);
163+
m_brush_ZoomRectColour = wxColour(32, 48, 64);
164+
m_brush_AxisColour = wxColour(24, 24, 24);
165+
m_pen_AxisColour = wxColour(96, 128, 160);
166+
m_pen_AxisColourZoom = wxColour(255, 128, 64);
167+
m_pen_AxisColourAutoZoom = wxColour(96, 128, 160);
168+
m_pen_AxisXColour = wxColour(80, 80, 80);
169+
m_pen_AxisYColour = wxColour(80, 80, 80);
170+
m_pen_AxisXTextColour = wxColour(255, 255, 255);
171+
m_pen_AxisYTextColour = wxColour(255, 255, 255);
172+
173+
m_brush_LegendColour = wxColour(32, 48, 64);
174+
m_brush_LegendSelectColour = wxColour(64, 96, 128);
175+
m_pen_LegendSelectColour = wxColour(128, 170, 212);
176+
m_pen_LegendSelectTextColour = wxColour(255, 255, 255);
177+
m_pen_LegendColour = wxColour(96, 128, 160);
178+
m_pen_LegendTextColour = wxColour(255, 255, 255);
179+
m_brush_MainColour = wxColour(0, 0, 0);
180+
m_pen_MainColour = wxColour(96, 128, 160);
181+
182+
m_pen_HeadTextColour = wxColour(255, 255, 255);
183+
m_pen_ProjectHeadTextColour = wxColour(255, 255, 255);
184+
185+
m_pen_GraphTotalColour = wxColour(255, 0, 0);
186+
m_pen_GraphRACColour = wxColour(0, 200, 0);
187+
m_pen_GraphTotalHostColour = wxColour(0, 128, 255);
188+
m_pen_GraphRACHostColour = wxColour(255, 200, 0);
189+
} else {
190+
m_pen_MarkerLineColour = wxColour(0, 0, 0);
191+
m_pen_ZoomRectColour = wxColour(128, 64, 95);
192+
m_brush_ZoomRectColour = wxColour(24, 31, 0);
193+
m_brush_AxisColour = wxColour(192, 224, 255);
194+
m_pen_AxisColour = wxColour(64, 128, 192);
195+
m_pen_AxisColourZoom = wxColour(255, 64, 0);
196+
m_pen_AxisColourAutoZoom = wxColour(64, 128, 192);
197+
m_pen_AxisXColour = wxColour(64, 128, 192);
198+
m_pen_AxisYColour = wxColour(64, 128, 192);
199+
m_pen_AxisXTextColour = wxColour(0, 0, 0);
200+
m_pen_AxisYTextColour = wxColour(0, 0, 0);
201+
202+
m_brush_LegendColour = wxColour(235, 255, 255);
203+
m_brush_LegendSelectColour = wxColour(192, 224, 255);
204+
m_pen_LegendSelectColour = wxColour(64, 128, 192);
205+
m_pen_LegendSelectTextColour = wxColour(0, 0, 0);
206+
m_pen_LegendColour = wxColour(64, 128, 192);
207+
m_pen_LegendTextColour = wxColour(0, 0, 0);
208+
m_brush_MainColour = wxColour(255, 255, 255);
209+
m_pen_MainColour = wxColour(64, 128, 192);
210+
211+
m_pen_HeadTextColour = wxColour(0, 0, 0);
212+
m_pen_ProjectHeadTextColour = wxColour(0, 0, 0);
213+
214+
m_pen_GraphTotalColour = wxColour(255, 0, 0);
215+
m_pen_GraphRACColour = wxColour(0, 160, 0);
216+
m_pen_GraphTotalHostColour = wxColour(0, 0, 255);
217+
m_pen_GraphRACHostColour = wxColour(0, 0, 0);
218+
}
188219

189220
m_dc_bmp.Create(1, 1);
190221
m_full_repaint = true;

0 commit comments

Comments
 (0)