Windows 10 Dark-Mode

Grafische Primitive, XbaseParts und Darstellungsfragen allgemein.

Moderator: Moderatoren

Antworten
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Windows 10 Dark-Mode

Beitrag von AUGE_OHR »

hi,

Ich gehöre ja zu denen die Nachts arbeiten und da ist das "weiss" doch sehr hell.
deshalb verwende ich auch den "Nachtmodus" aber langsam gefällt mir auch der Dark-Modus wie ihn auch Firefox übernimmt.

nun frage ich mich wie ich meine Xbase++ Apps auf Dark-Modus umstellen kann.
wenn es ein visual Style wäre müsste es ja automatisch passieren wenn ich die Konstanten verwende, oder :idea:

wenn ich nun die Farben meiner Apps ändere komme ich nicht an alle Sachen, z.b. Frame. ran ...
hat da jemand schon eine Lösung :?:
gruss by OHR
Jimmy
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Re: Windows 10 Dark-Mode

Beitrag von AUGE_OHR »

hi,

Ich habe mal angefangen eine App für den Darkmode Style vorzubereiten um zu testen an welchen Stellen man mit Farbe nicht weiter kommt.
Win32 - Unter Windows können die Systemfarben für xxx nicht durch Presentation-Parameter geändert werden.
im Optimalen Fall würde man im MAIN Dialog die gewünschten Presentation-Parameter und alle folgenden Controls erben die. eigene Farben gehen aber nur wenn kein Visual Style dazwischen funkt, also bei

Code: Alles auswählen

o:useVisualStyle := .F.
bei XbParts wie XbpPushbutton() hilft das nun nicht weil o.g. Win32 Beschränkung eintritt. Dagegen hilft nur Owner Draw. damit fallen alle Common Dialog raus, wie auch die Msgbox(), da man dort kein Owner Draw machen kann.

ich habe nun folgende Erweiterungen :

Tabpage : Header mit Owner Draw aber ohne visual Effects
Pushbutton : Owner Draw mit visual Effect "Hover"
SLE : Frame in blau mit Owner Draw
XbpBrowse Header : Owner Draw statt visual Effect


so sieht es nun aus
SLE_WEISS_Farbe.PNG
SLE_WEISS_Farbe.PNG (57.04 KiB) 5709 mal betrachtet
oder so
SLE_GRAU_Farbe.PNG
SLE_GRAU_Farbe.PNG (56.19 KiB) 5709 mal betrachtet
ich bin mir nicht sicher welches Design mit den SLE mir besser gefällt.
mit vielen weissen SLE ist es mir zu hell und das grau ...

p.s. mit dieses kleine Tool kann man schnell hell/dunkel umschalten https://www.wintools.info/index.php/easy-dark-mode
gruss by OHR
Jimmy
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Re: Windows 10 Dark-Mode

Beitrag von AUGE_OHR »

und weiter geht es mit Darkmode.

die Farbe von Scrollbar kann man wohl nicht ändern :(

auch bei meinen DXE Controls lief nicht gleich alles im Darkmode

DXE_STATBAR() mit Owner Draw des "Panel". die "Bevel" (Trenner) sind immer noch hell und nur die "internen" reagieren auf Farbe ...
DXE_TOOLBAR() & DXE_REBAR() da gibt es kein Owner Draw. Es gibt aber Customdraw ( nicht der Abklasch von XbpBrowse )

https://docs.microsoft.com/en-us/window ... ustom-draw
das gilt für die folgenden Controls
Header controls
List-view controls
Rebar controls
Toolbar controls
Tooltip controls
Trackbar controls
Tree-view controls
---

Ich habe zwar Customdraw im DXE_Listview() aber für den Darkmode müsste man noch einen Trick verwenden.
Leer_Listview.jpg
Leer_Listview.jpg (327.95 KiB) 5642 mal betrachtet
wie man sieht ist das Problem wenn das Browse nicht vollständig gefüllt ist. da kann Customdraw nichts malen ...

nun kann man ein Listview mit einem Hintergrundbild belegen
HBM_Listview.jpg
HBM_Listview.jpg (166.29 KiB) 5642 mal betrachtet
gruss by OHR
Jimmy
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Re: Windows 10 Dark-Mode

Beitrag von AUGE_OHR »

moin,

bei DXE_Statbar() habe ich raus bekommen warum nur die "internen" Panel auf Farbe reagierten.
da Farbe nur mit Owner Draw funktioniert muss

Code: Alles auswählen

   nBevel := SBT_OWNERDRAW
verwendet werden

Code: Alles auswählen

   IF nBevel = SBT_OWNERDRAW .AND. ::DrawMode <> XBP_DRAW_NORMAL
hab jetzt auch Custom-Draw in DXE_Toolbar eingebaut und die Pres-Parameter aktiviert.
es verschwindet immer mehr Weiss ;)
XCM_Blue1.jpg
XCM_Blue1.jpg (455.68 KiB) 5578 mal betrachtet
Blau hab zum testen genommen denn Schwarz könnte auch ein "falsches" Resultat sein.

-- todo

beim DCE_TabCtl() stimmt die Farbe des (aktiven) Tab-Header noch nicht.
im Listview hat der Header noch visual Style
und die CMD-ComboBox muss noch umgestellt werden.

btw. den Listbox Teil der Combo mache ich per Ownerdraw und was/wie mache ich es mit dem SLE Teil der Combobox :?:
gruss by OHR
Jimmy
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Re: Windows 10 Dark-Mode

Beitrag von AUGE_OHR »

moin,

ich hatte ja das Owner Draw in DXE_TabCtl() eingebaut. jetzt wollte ich es verwenden
nun ging das mit den Farben aber die Caption stimmte nicht wenn man z.b. das Verzeichnis gewechselt hat.

laut Anweisung von Microsoft geht es ganz einfach ...
https://docs.microsoft.com/en-us/window ... cm-getitem

Code: Alles auswählen

  LOCAL lRet
  LOCAL oItem
  LOCAL nSize := 200
  LOCAL cText := SPACE(nSize)

  oItem := TCITEM() :NEW()
  oItem:mask := TCIF_TEXT
  oItem:pszText := cText + CHR( 0 )
  oItem:cchTextMax := LEN( cText ) + 1

  lRet := @USER32:SendMessageA( ::hTabCtl, TCM_GETITEM, nitemID, oItem )
  IF lRet > 0
     cText := oItem:pszText
nur dummerweise kommt da nichts ... :(

beim suchen nach Beispielen fand ich diesen Artikel
https://autohotkey.com/board/topic/1646 ... m-getitem/

ich sah was mit

Code: Alles auswählen

DllCall( "VirtualAllocEx" ...)
DllCall( "WriteProcessMemory" ... )
DllCall( "ReadProcessMemory" ... )
hm ... das hab ich doch schon mal gesehen ...

JA gefunden : GETDESK.PRG :D

es ging darum die Position der Icons auf dem Desktop festzustellen.
Problem : man kann sich nicht in die aktuelle Instanz einklinken
Workaround : "virtuellen Speicher" als Kopie nutzen

Code: Alles auswählen

   @User32:GetWindowThreadProcessId(::hTabCtl,@processId)
   process := @Kernel32:OpenProcess(procFlags, .F. , processId)

   GlobalBuffer  := @Kernel32:VirtualAllocEx(process, NULL, nSize, MemFlags, PAGE_READWRITE)

   oItem := TCITEM() :NEW()
   oItem:mask := TCIF_TEXT
   oItem:pszText := GlobalBuffer // <- virtueller Speicher
   oItem:cchTextMax := nSize

   pSizeString := oItem:_sizeof_()
   GlobalStruct  := @Kernel32:VirtualAllocEx(process, NULL, pSizeString, MemFlags, PAGE_READWRITE)
   @Kernel32:WriteProcessMemory(process, GlobalStruct, @oItem , pSizeString, NULL)
   @Kernel32:WriteProcessMemory(process, GlobalBuffer, @oItem , pSizeString, NULL)

   // jetzt "lesen"
   lRet := @USER32:SendMessageA( ::hTabCtl, TCM_GETITEM, nitemID , oItem )

   cBuffer := SPACE(nSize)+CHR(0)
   @Kernel32:ReadProcessMemory(process, GlobalBuffer, @cBuffer, pSizeString, NULL)
ja das Problem hab ich nun behoben und nun das nächste ;)
XCM_TAB_Bereich.jpg
XCM_TAB_Bereich.jpg (159.18 KiB) 5473 mal betrachtet
wie man sehen kann gibt esbei Ownerdraw einen Bereich der für weitere Tabs oder Buttons am rechten Rand.
wenn der nun nicht gefüllt ist sieht man wieder eine Menge Weiss :(
gruss by OHR
Jimmy
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Re: Windows 10 Dark-Mode

Beitrag von AUGE_OHR »

moin,

ich habe eine ganze Zeit lang an der TAB Area getüftelt und die Lösung war ganz einfach :)
wenn ich mit Listview Owner Draw fertig bin errechne ich den Platz von den Tabs

Code: Alles auswählen

   FOR i := 1 TO iMax
      aItemRect := ::GetItemRect(i-1)
      nWide += (aItemRect[3]-aItemRect[1])
      nWide += 1
   NEXT

   aRect[1] := nWide
   aRect[2] := 0
   aRect[3] := aSize[1]
   aRect[4] := 64
damit fülle ich dann den Bereich hinter den Tabs auf. :badgrin:
ein leichtes flackern ist vorhanden wenn sich ein Tab ändert aber eben nur dann.

so damit bin ich fast durch ... "nur" noch der Header des Listview ist noch weiss.

nun stellte ich leider fest das es kaumr keine Methoden für den Zugriff auf den Listview-Header gibt :?:
das einzige was der Listview Wrapper von Pablo bietet ist

Code: Alles auswählen

   pHead  := ::lv_GetHeader()
also nur ein Handle zur HDITEM Structure.

ich konnte zwar die Zeile, per Ownerdraw, malen aber beim nächsten klick ... war alles wieder weiss :angry4:
SubClass_not_Stable.jpg
SubClass_not_Stable.jpg (320.35 KiB) 5438 mal betrachtet
---

nach langen Recherchen stellte ich heraus das der Listview-Header ein "WC_HEADER" Control ist :banghead:
man könnte es vergleichen mit einem Scrollbar von einem XbpDialog wo man "so" nicht einfach ran kommt.

die Lösung heisst SubClass mit ot4xb ... was eine längere Geschichte wurde ...
gruss by OHR
Jimmy
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Re: Windows 10 Dark-Mode

Beitrag von AUGE_OHR »

moin,

SubClass mittels ot4xb war klar aber wie löse ich ein Owner Draw des Listview Header aus ?

Code: Alles auswählen

   ot4xb_subclasswindow( ::hLv , MyHeadHandler() :New( self ), NIL,"Head_wndproc" )
es kam nichts an ... ja bei Listview hab ich Ownerdraw / Customdraw aktiviert.

Code: Alles auswählen

INLINE METHOD Head_wndproc(hWnd,nMsg,wp,lp,ctx)
LOCAL rc := {0,0,0,0}
   Ondummy("Head_wndproc",TIME())
   IF nMsg == WM_DRAWITEM
      Ondummy("WM_DRAWITEM",TIME())
      ::Head_DrawItem(wp,lp,hWnd)
also fehlt mir hier noch noch die "Aktivierung" des Owner Draw vom "WC_HEADER" Control.
üblicherweise gibt es eine Konstante wie LVS_OWNERDRAWFIXED für Listview.

unter "WC_HEADER" hab ich nun HDF_OWNERDRAW gefunden ... aber der 3th Buchstabe ist ein "F" und kein "N"

ein "N" steht für Notify Event. diese würde man abfangen und darauf reagieren z.b. per EVAL(Codebock)
ein "F" steht hier nun für Format ... damit bestückt man die FMT Member einer Structure.

---

das einzige was der Listview Wrapper von Pablo bietet ist

Code: Alles auswählen

   pHead  := ::lv_GetHeader()
also nur ein Handle zu einer Structure.

ich hatte es dann über die HDITEM Structure versucht.
https://docs.microsoft.com/en-us/window ... -_hd_itema

Code: Alles auswählen

      oHDITEM  := HDITEM():New()
      oHDITEM:fmt := HDF_OWNERDRAW
      oHDITEM:mask := HDI_TEXT
      oHDITEM:pszText := cBuf
      oHDITEM:cchTextMax := LEN(cBuf)
das "lesen/schreiben" der Structure ist kein Problem aber "wann" soll das passieren wenn man keinen Event hat ... :^o

es funktionierte z.b. wenn dem man auf den Header klickt und einen Event auslöst den man dann zum "malen" nutzen kann. Nein ... das lief nicht richtig ... aber wo solle ich die Konstante HDF_OWNERDRAW sonst verwenden ... :?:

---

nun gibt es auch weitere HDF_* Konstanten wie für die "Sortier-Pfeile" und deren Ausrichtung.

Code: Alles auswählen

      IF Alignment = LVCFMT_LEFT
         oLVCol2:fmt := nor(oLVCol2:fmt,HDF_LEFT ,HDF_BITMAP_ON_RIGHT )
      ELSE
         oLVCol2:fmt := nor(oLVCol2:fmt,HDF_RIGHT,HDF_BITMAP )
      ENDIF

      IF ::SortOrder == LVS_SORTASCENDING
         oLVCol2:fmt := nOr(oLVCol2:fmt,HDF_SORTUP  ) // this make the Icon !
      ELSE
         oLVCol2:fmt := nOr(oLVCol2:fmt,HDF_SORTDOWN) // this make the Icon !
      ENDIF
das ganze geht an die LVCOLUMN() Structure ... hm ... :-k

wir sind der Lösung schon ganz nahe ... wer hat eine Idee :idea:
die Lösung gibt es in der nächsten Msg :D
XCM_Black1.jpg
XCM_Black1.jpg (290.64 KiB) 5379 mal betrachtet
gruss by OHR
Jimmy
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Re: Windows 10 Dark-Mode

Beitrag von AUGE_OHR »

moin,

der vorherige Code stammt aus der Aktion von einem klick auf den Listview Header.
damit wählt man eine Column aus aber dort wirkt ein setzten der HDF_OWNERDRAW Konstante nicht :(

also habe ich weiter nach HDF_OWNERDRAW gesucht und irgendwann ein "komisches" Beispiel gefunden ... :shock:
aber der Weg funktionierte :blob8:

das "komische" war das die HDF_OWNERDRAW Konstante mit einer LVCOLUMN() Strukture verwenden wurde wo sonst nur LVCFMT_* Konstanten standen. das man die kombinieren kann war mir nicht klar aber es funktioniert :!:

Code: Alles auswählen

METHOD DXE_ArrayView:InitTheListView()
  ...     
      // add Ownerdraw
      ::oLVCol:fmt := nOr(::oLVCol:fmt, HDF_OWNERDRAW)
      // insert Column now
      ::lv_InsertColumn(n-1,::oLVCol)
   NEXT

   IF !EMPTY(::lv_GetHeader())
      // switch Theme OFF for Ownerdraw
      @UxTheme:SetWindowTheme(::lv_GetHeader(),CHR(0),CHR(0))
      // Subclass 
      ot4xb_subclasswindow(::hLv,MyHeadHandler():New(self),NIL,"Head_wndproc")
   ENDIF
nach anlegen jeder Column und vor dem Insert jeder Column muss man die Konstante HDF_OWNERDRAW einsetzten dann bekommt man beim SubClass auch die WM_DRAWITEM Message :!:

es fehlen noch die up/down Icons ... hm ... welche nimmt man da ...
ja man könnte mit WingDings etc. was machen ... aber noch einen Font nur für 1 Zeichen ...

also hab ich nun Windows System Icon genommen

Code: Alles auswählen

   ::IcoUp := DXE_Icon() :new() :create()
   ::IcoUp:load( WinDir+"\System32\NetShell.dll", 2301,16,16 )

   ::IcoDn := DXE_Icon() :new() :create()
   ::IcoDn:load( WinDir+"\System32\NetShell.dll", 2300,16,16 )
wie man an solche System Icon kommt siehe hier

Code: Alles auswählen

https://www.xbaseforum.de/viewtopic.php?f=16&t=8808&p=125442
damit hätte ich es, bis auf die Scrollbar, geschafft das man die Farben der Controls verändern kann.
jetzt fehlen nur noch die "richtigen" Farben denn der Windows 10 Darkmode ist mehr als nur Schwarz
XCM_Black3.JPG
XCM_Black3.JPG (194.41 KiB) 5335 mal betrachtet
gruss by OHR
Jimmy
Antworten