Better ColorRequester()

Share your advanced PureBasic knowledge/code with the community.
User avatar
ChrisR
Addict
Addict
Posts: 1127
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: Better ColorRequester()

Post by ChrisR »

It is not 24 bit for RGB and 32 bit for RGBA? anyway long seems enough
#
It is probably best to open ChooseColor non-expanded by default, without #CC_FULLOPEN flag.
The Define Custom Color button is here to display the custom color controls, if needed.
Once expanded, the button is disabled and we can not go back to display it non-expanded.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Better ColorRequester()

Post by Kwai chang caine »

Thanks at you two for sharing 8)
ImageThe happiness is a road...
Not a destination
Little_man
Enthusiast
Enthusiast
Posts: 143
Joined: Fri Mar 29, 2013 4:55 pm
Location: The Netherland

Re: Better ColorRequester()

Post by Little_man »

Thanks Chris,

Question:
How can I change the text of the title bar ?

Little_man
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: Better ColorRequester()

Post by Mijikai »

ChrisR wrote:It is not 24 bit for RGB and 32 bit for RGBA?.
32 bits / 8 (Bits for 1 Byte) -> 4 Bytes
IdeasVacuum
Always Here
Always Here
Posts: 6425
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Better ColorRequester()

Post by IdeasVacuum »

How can the position of the FullColorRequester be set?

If my program is Screen Centred, the requester @ x0 y0 on a wide screen is miles away :D
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
ChrisR
Addict
Addict
Posts: 1127
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: Better ColorRequester()

Post by ChrisR »

If you use the last code here, without the test at the bottom.
Edit: I added a parameter for the initial color selected and CompilerIf (#PB_Compiler_IsMainFile) for the exemple.
Just sends the X and Y position to FullColorRequester(InitialColor, X, Y). ex:

Code: Select all

Removed, see code 4 post below
Last edited by ChrisR on Thu Dec 08, 2022 4:30 pm, edited 1 time in total.
IdeasVacuum
Always Here
Always Here
Posts: 6425
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Better ColorRequester()

Post by IdeasVacuum »

Thanks ChrisR, I didn't study your update of the code :oops:
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
IdeasVacuum
Always Here
Always Here
Posts: 6425
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Better ColorRequester()

Post by IdeasVacuum »

[deleted]
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
ChrisR
Addict
Addict
Posts: 1127
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: Better ColorRequester()

Post by ChrisR »

Going through an extra window for the position is not really great because the main window is not locked. You can click on the buttons,... while the color requester is still open.

I found better for the position and optionally the requester backgound color, by using #CC_ENABLEHOOK in ChooseColor\flags.
I will publish tomorrow.
User avatar
ChrisR
Addict
Addict
Posts: 1127
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: Better ColorRequester()

Post by ChrisR »

FullColorRequester revision with its position and optionally the background color of the Requester.
See Usage in FullColorRequester.pb

Image

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
Post Reply