FullColorRequester revision with its position and optionally the background color of the Requester.
See Usage in FullColorRequester.pb
Code: Select all
;- Top
;============================================================================
; Author: blueb
; Date: May 8, 2017 - Rev. Dec 8, 2022
; Explain: Create a new ColorRequester that saves User Colors (between calls)
; Forum: http://www.purebasic.fr/english/viewtopic.php?f=12&t=68450
; Saved as: FullColorRequester.pb
; Addition: ChrisR: COLORREF array
; EnableHook for the ColorRequester Position and Set the ColorRequester Background Color.
; For Windows 10 and up, Buttons use the DarkMode_Explorer theme If the Background Color is Dark.
; ---------------------------------------------------------------------------
; Goal - write a 'Unique' preference file in the temporary directory that
; stays in the temporary directory even when user switches to other programs.
; It will keep the special colors the user last adjusted.
; ---------------------------------------------------------------------------
; msdn ChooseColor function: https://msdn.microsoft.com/en-us/library/windows/desktop/ms646912%28v=vs.85%29.aspx
;============================================================================
; Usage:
; FullColorRequester([Color = #PB_Default [, X = #PB_Default [, Y = #PB_Default [, BackColor = #PB_Default]]]])
;
; - Color : Default Color Selected
; | #PB_Default = No Color pre-selected
; - X, Y : Requester's position.
; | If Called from an active Window :
; | X, Y position inside the Window, scaling inside based on DPI
; | #PB_Default = Mouse position in the window's internal area.
; | Else
; | X, Y position, scaling inside based on DPI
; | #PB_Default = Desktop mouse position
; | EndIf
;
; - BackColor : Requester Background Color
; | #PB_Default = Default Background Color
;============================================================================
EnableExplicit
Declare IsDarkCColor(Color)
Declare CColorEnumChild(hWnd, lParam)
Declare ChooseColorProc(hWnd, uMsg, wParam, lParam)
Declare InitColorPrefs()
Declare ExitColorPrefs()
Declare FullColorRequester(Color = #PB_Default, X = #PB_Default, Y = #PB_Default, BackColor = #PB_Default)
Structure COLORREF
RGB.l[16]
EndStructure
; Structure CHOOSECOLOR ; see PB toolbox
; lStructSize.l
; hwndOwner.i
; hInstance.i
; rgbResult.l
; *lpCustColors
; Flags.l
; lCustData.i
; *lpfnHook
; *lpTemplateName
; EndStructure
; Needed for preferences file.
Global.i Dim COLORPREF(15)
Global CColorX, CColorY, CColorBackGround
Procedure IsDarkCColor(Color)
If Red(Color)*0.299 + Green(Color)*0.587 +Blue(Color)*0.114 < 128 ; Based on Human perception of color, following the RGB values (0.299, 0.587, 0.114)
ProcedureReturn #True
EndIf
ProcedureReturn #False
EndProcedure
Procedure CColorEnumChild(hWnd, lParam)
Protected sClassName.s{64}
GetClassName_(hWnd, @sClassName, SizeOf(sClassName))
;Protected sText.s{1024} : GetWindowText_(hWnd, @sText, SizeOf(sText)) : Debug " CHILD: Class=" + sClassName + " - " + "Text=" + sText
If sClassName = "Button"
SetWindowTheme_(hWnd, "DarkMode_Explorer", 0)
EndIf
ProcedureReturn #True
EndProcedure
Procedure ChooseColorProc(hWnd, uMsg, wParam, lParam)
Protected DesktopRect.Rect, Rect.Rect
Static CColorBrush, CCFrontColor
Select uMsg
Case #WM_NCDESTROY
If CColorBackGround <> #PB_Default
DeleteObject_(CColorBrush)
EndIf
Case #WM_INITDIALOG
; Mini and Maxi position X, Y to stay in Desktop work area
SystemParametersInfo_(#SPI_GETWORKAREA, 0, @DesktopRect, 0)
GetWindowRect_(hWnd, Rect)
; X, Y > 0
If CColorX < DesktopRect\left : CColorX = DesktopRect\left : EndIf
If CColorY < DesktopRect\top : CColorY = DesktopRect\top : EndIf
; Positioned the other way, from the right and bottom side, if too large to fit in the desktop work area
If CColorX + (Rect\right - Rect\left) > (DesktopRect\right - DesktopRect\left) : CColorX - (Rect\right - Rect\left) : EndIf
If CColorY + (Rect\bottom - Rect\top) > (DesktopRect\bottom - DesktopRect\top) : CColorY - (Rect\bottom - Rect\top) : EndIf
; If X, Y are always too large, set the maximum position to stay in Desktop work area
If CColorX + (Rect\right - Rect\left) > (DesktopRect\right - DesktopRect\left) : CColorX = (DesktopRect\right - DesktopRect\left) - (Rect\right - Rect\left) : EndIf
If CColorY + (Rect\bottom - Rect\top) > (DesktopRect\bottom - DesktopRect\top) : CColorY = (DesktopRect\bottom - DesktopRect\top) - (Rect\bottom - Rect\top) : EndIf
SetWindowPos_(hWnd, #HWND_TOPMOST, CColorX, CColorY, 0, 0, #SWP_NOSIZE)
If CColorBackGround <> #PB_Default
CColorBrush = CreateSolidBrush_(CColorBackGround)
If IsDarkCColor(CColorBackGround)
CCFrontColor = #White
If OSVersion() >= #PB_OS_Windows_10
EnumChildWindows_(hWnd, @CColorEnumChild(), 0)
EndIf
Else
CCFrontColor = #Black
EndIf
EndIf
ProcedureReturn #False
Case #WM_CTLCOLORDLG, #WM_CTLCOLORSTATIC, #WM_CTLCOLOREDIT
If CColorBackGround <> #PB_Default
SetTextColor_(wParam, CCFrontColor)
SetBkMode_(wParam, #TRANSPARENT)
ProcedureReturn CColorBrush
EndIf
EndSelect
ProcedureReturn #False
EndProcedure
Procedure InitColorPrefs() ;Color Preference file - Storage information
Protected I.l
If OpenPreferences(GetTemporaryDirectory() + "GetUserColors.prefs") ;It exists, retrieve the GetUserColors.prefs information
For I = 0 To 15
COLORPREF(I) = ReadPreferenceInteger("COLORREF"+Str(I+1), COLORPREF(I))
Next
Else ; Does not exist, "GetUserColors.prefs" is erased. So create it with Default values
CreatePreferences(GetTemporaryDirectory() + "GetUserColors.prefs")
For I = 0 To 15
WritePreferenceInteger("COLORREF"+Str(I+1), COLORPREF(I))
Next
ClosePreferences()
EndIf
EndProcedure
Procedure ExitColorPrefs()
Protected I.i
If OpenPreferences(GetTemporaryDirectory() + "GetUserColors.prefs")
For I = 0 To 15
WritePreferenceInteger("COLORREF"+Str(I+1), COLORPREF(I))
Next
ClosePreferences()
EndIf
EndProcedure
Procedure FullColorRequester(Color = #PB_Default, X = #PB_Default, Y = #PB_Default, BackColor = #PB_Default) ;Place CHOOSECOLOR Info into requester()
Protected CHOOSECOLOR.CHOOSECOLOR, COLORREF.COLORREF, I
Protected hwnd = GetActiveWindow()
InitColorPrefs()
CColorBackGround = BackColor
;Place saved colors inside requester()
For I = 0 To 15
COLORREF\RGB[I] = COLORPREF(I)
Next
CHOOSECOLOR\LStructSize = SizeOf(CHOOSECOLOR)
If IsWindow(hwnd) ;Window Owner
CHOOSECOLOR\hwndOwner = WindowID(hwnd)
If X = #PB_Default
CColorX = DesktopScaledX(WindowX(hwnd, #PB_Window_InnerCoordinate)) + WindowMouseX(hwnd) ; WindowX() + Horizontal mouse position in the window's internal area
Else
CColorX = DesktopScaledX(WindowX(hwnd, #PB_Window_InnerCoordinate) + X) ; WindowX() + X value after scaling, based on Horizontal DPI
EndIf
If Y = #PB_Default
CColorY = DesktopScaledY(WindowY(hwnd, #PB_Window_InnerCoordinate)) + WindowMouseY(hwnd) ; WindowY() + Vertical mouse position in the window's internal area
Else
CColorY = DesktopScaledY(WindowY(hwnd, #PB_Window_InnerCoordinate) + Y) ; WindowY() + Y value after scaling, based on Horizontal DPI
EndIf
Else ;No Owner
CHOOSECOLOR\hwndOwner = 0
If X = #PB_Default
CColorX = DesktopMouseX() ; Absolute Horizontal position of the desktop mouse
Else
CColorX = DesktopScaledX(X) ; X value after scaling, based on Horizontal DPI
EndIf
If Y = #PB_Default
CColorY = DesktopMouseY() ; Absolute Y position of the desktop mouse
Else
CColorY = DesktopScaledY(Y) ; Y value after scaling, based on Vertical DPI
EndIf
EndIf
CHOOSECOLOR\rgbResult = Color ;Default color
CHOOSECOLOR\lpCustColors = COLORREF
CHOOSECOLOR\lpfnHook = @ChooseColorProc()
;CHOOSECOLOR\flags = #CC_ANYCOLOR | #CC_RGBINIT | #CC_ENABLEHOOK
CHOOSECOLOR\flags = #CC_FULLOPEN |#CC_ANYCOLOR | #CC_RGBINIT | #CC_ENABLEHOOK ;#CC_FULLOPEN to display the additional controls
If ChooseColor_(@CHOOSECOLOR)
For I = 0 To 15
COLORPREF(I) = COLORREF\RGB[I]
Next
ExitColorPrefs() ;Save info and Return Color Selected
ProcedureReturn CHOOSECOLOR\rgbResult
Else ;No color was selected
ExitColorPrefs() ;Save info and Return Default Color
ProcedureReturn #PB_Default
EndIf
EndProcedure
;- example
CompilerIf (#PB_Compiler_IsMainFile)
Macro DebugColor(_Color_)
If _Color_ = #PB_Default
Debug "Canceled by User or No Color Selected, Default Color (#PB_Default)"
Else
Debug "Color Selected: " + _Color_ +
" - Hex: " + "$" + RSet(Hex(Blue(_Color_)), 2, "0") + RSet(Hex(Green(_Color_)), 2, "0") + RSet(Hex(Red(_Color_)), 2, "0") +
" - RGB(" + Str(Red(_Color_)) + ", " + Str(Green(_Color_)) + ", " + Str(Blue(_Color_)) + ")"
EndIf
EndMacro
Define Color
Color = FullColorRequester() ; No color pre-selected, Desktop mouse position. No Background Color
DebugColor(Color)
Color = FullColorRequester($2C0408, 300, 200, $160204)
DebugColor(Color)
Color = FullColorRequester(Color, #PB_Default, #PB_Default, Color) ; Desktop mouse position (previous click on Close, OK or Cancel Button)
;Color = FullColorRequester(Color) ; Desktop mouse position (previous click on Close, OK or Cancel Button). No Background Color
DebugColor(Color)
Color = FullColorRequester(Color, -20, -20, Color)
DebugColor(Color)
Color = FullColorRequester(Color, 3840+20, 2160+20)
DebugColor(Color)
CompilerEndIf
A small demo is already included but if needed, here is another demo with the call from a window:
Code: Select all
EnableExplicit
Enumeration Window
#Window_0
EndEnumeration
Enumeration Gadgets
#Btn_Pick_Color
#Txt_Color
EndEnumeration
XIncludeFile "FullColorRequester.pb"
Procedure Resize_Window_0()
Protected.f ScaleX, ScaleY
Static Window_0_WidthIni, Window_0_HeightIni
If Window_0_WidthIni = 0
Window_0_WidthIni = WindowWidth(#Window_0) : Window_0_HeightIni = WindowHeight(#Window_0)
EndIf
ScaleX = WindowWidth(#Window_0) / Window_0_WidthIni : ScaleY = WindowHeight(#Window_0) / Window_0_HeightIni
ResizeGadget(#Btn_Pick_Color, ScaleX * 40, ScaleY * 40, ScaleX * (Window_0_WidthIni - 80), ScaleY * (Window_0_HeightIni - 90))
ResizeGadget(#Txt_Color, 10, WindowHeight(#Window_0) - 30, WindowWidth(#Window_0) - 20, #PB_Ignore)
EndProcedure
Procedure SetColor(Color)
SetWindowColor(#Window_0, Color)
SetGadgetText(#Txt_Color, "RGB(" + Str(Red(Color)) + ", " + Str(Green(Color)) + ", " + Str(Blue(Color)) + ")" +
" or $" + RSet(Hex(Blue(Color)), 2, "0") + RSet(Hex(Green(Color)), 2, "0") + RSet(Hex(Red(Color)), 2, "0"))
SetGadgetColor(#Txt_Color, #PB_Gadget_BackColor, Color)
If IsDarkCColor(Color) : SetGadgetColor(#Txt_Color, #PB_Gadget_FrontColor, #White) : Else : SetGadgetColor(#Txt_Color, #PB_Gadget_FrontColor, #Black) : EndIf
EndProcedure
Procedure Open_Window_0(X = 0, Y = 0, Width = 200, Height = 140)
If OpenWindow(#Window_0, X, Y, Width, Height, "Color", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_SizeGadget | #PB_Window_ScreenCentered)
ButtonGadget(#Btn_Pick_Color, 40, 40, 120, 50, "Pick Color", #PB_Button_Default)
TextGadget(#Txt_Color, 10, 110, 180, 17, "", #PB_Text_Center)
BindEvent(#PB_Event_SizeWindow, @Resize_Window_0(), #Window_0)
PostEvent(#PB_Event_SizeWindow, #Window_0, 0)
EndIf
EndProcedure
CompilerIf (#PB_Compiler_IsMainFile)
Define Color = $160204
Open_Window_0()
SetColor(Color)
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Break
Case #PB_Event_Gadget
Select EventGadget()
Case #Btn_Pick_Color
;- Exemple
;Color = FullColorRequester(Color, GadgetX(#Btn_Pick_Color) + GadgetWidth(#Btn_Pick_Color), GadgetY(#Btn_Pick_Color) + GadgetHeight(#Btn_Pick_Color), Color)
Color = FullColorRequester(Color, #PB_Default, #PB_Default, Color) ; Mouse position in the window's internal area
;Color = FullColorRequester(Color) ; Mouse position in the window's internal area. Default Background Color
;Color = FullColorRequester() ; No Color pre-selected. Mouse position in the window's internal area. Default Background Color
SetColor(Color)
EndSelect
EndSelect
ForEver
CompilerEndIf