1. Responding to system color changes

I know this is trivial, but if a user changes the system color scheme 
within Windows while your win32lib based program is running, the 
background colors for all your controls are the same as when the program 
started.  Not a big deal, but it would be nice if win32lib based 
programs responded to these color changes like other Windows programs.  

To that end, I submit the following routine that I use.  The beauty is 
you don't have to code all the controls to be changed, the routine will 
change all child windows/controls based on the passed parent.  So if you 
have a main window with several child windows and they have controls and 
child windows and so on, this routine will work.


procedure setChildColor(integer parent, atom color)
	sequence children

	children = findChildren(parent)
	for i = 1 to length(children) do
		if children[i][2] = Window then
			setWindowBackColor(children[i][1], color)
		end if
		if 
find(children[i][2],{PushButton,DefPushButton,LText,Radio,CheckBox}) 
then
			setWindowBackColor(children[i][1], color)	
		elsif children[i][2]=Group then
			setWindowBackColor(children[i][1],color)
			setChildColor(children[i][1],color)
		else
			setChildColor(children[i][1], color)
		end if
	end for

end procedure

In context, here's how I use it:

atom cur_color

procedure Main_onPaint (integer self, integer event, sequence 
params)--params is ( int x1, int y1, int x2, int y2 )
	object color
        color = getSysColor(COLOR_BTNFACE)
	if color != cur_color then
		cur_color = color
		setWindowBackColor(Main, color)
		setChildColor(Main, color)
	end if
end procedure
setHandler( Main, w32HPaint, routine_id("Main_onPaint"))

new topic     » topic index » view message » categorize

2. Re: Responding to system color changes

According to MSDN, the message for this is WM_SYSCOLORCHANGE. Here are some 
of the remarks...

-=-
The system sends a WM_PAINT message to any window that is affected by a 
system color change.

Applications that have brushes using the existing system colors should 
delete those brushes and recreate them using the new system colors.

Top level windows that use common controls must forward the 
WM_SYSCOLORCHANGE message to the controls; otherwise, the controls will not 
be notified of the color change. This ensures that the colors used by your 
common controls are consistent with those used by other user interface 
objects. For example, a toolbar control uses the "3D Objects" color to draw 
its buttons. If the user changes the 3D Objects color but the 
WM_SYSCOLORCHANGE message is not forwarded to the toolbar, the toolbar 
buttons will remain in their original color while the color of other buttons 
in the system changes.
-=-

  So, what would be needed is to recreate any system brushes that win32lib 
might have and SendMessage() the WM_SYSCOLORCHANGE notification to all 
common controls.

>From: Jonas  Temple <jtemple at yhti.net>
>Reply-To: EUforum at topica.com
>To: EUforum <EUforum at topica.com>
>Subject: Responding to system color changes
>Date: Fri, 14 Mar 2003 16:30:28 +0000
>
>
>I know this is trivial, but if a user changes the system color scheme
>within Windows while your win32lib based program is running, the
>background colors for all your controls are the same as when the program
>started.  Not a big deal, but it would be nice if win32lib based
>programs responded to these color changes like other Windows programs.
>
>To that end, I submit the following routine that I use.  The beauty is
>you don't have to code all the controls to be changed, the routine will
>change all child windows/controls based on the passed parent.  So if you
>have a main window with several child windows and they have controls and
>child windows and so on, this routine will work.
>
>
>procedure setChildColor(integer parent, atom color)
>	sequence children
>
>	children = findChildren(parent)
>	for i = 1 to length(children) do
>		if children[i][2] = Window then
>			setWindowBackColor(children[i][1], color)
>		end if
>		if
>find(children[i][2],{PushButton,DefPushButton,LText,Radio,CheckBox})
>then
>			setWindowBackColor(children[i][1], color)
>		elsif children[i][2]=Group then
>			setWindowBackColor(children[i][1],color)
>			setChildColor(children[i][1],color)
>		else
>			setChildColor(children[i][1], color)
>		end if
>	end for
>
>end procedure
>
>In context, here's how I use it:
>
>atom cur_color
>
>procedure Main_onPaint (integer self, integer event, sequence
>params)--params is ( int x1, int y1, int x2, int y2 )
>	object color
>         color = getSysColor(COLOR_BTNFACE)
>	if color != cur_color then
>		cur_color = color
>		setWindowBackColor(Main, color)
>		setChildColor(Main, color)
>	end if
>end procedure
>setHandler( Main, w32HPaint, routine_id("Main_onPaint"))
>
>
>
>TOPICA - Start your own email discussion group. FREE!

new topic     » goto parent     » topic index » view message » categorize

3. Re: Responding to system color changes

----- Original Message ----- 
From: "Jonas Temple" <jtemple at yhti.net>
To: "EUforum" <EUforum at topica.com>
Subject: Responding to system color changes


> 
> I know this is trivial, but if a user changes the system color scheme 
> within Windows while your win32lib based program is running, the 
> background colors for all your controls are the same as when the program 
> started.  Not a big deal, but it would be nice if win32lib based 
> programs responded to these color changes like other Windows programs.  

This is already on my todo list. 

----------
Derek

new topic     » goto parent     » topic index » view message » categorize

4. Re: Responding to system color changes

***********************************************************

Jonas Temple wrote:
> > I know this is trivial, but if a user changes the system color scheme
> > within Windows while your win32lib based program is running, the
> > background colors for all your controls are the same as when the program
> > started.  Not a big deal, but it would be nice if win32lib based
> > programs responded to these color changes like other Windows programs.

Derek Parnell wrote:
> This is already on my todo list.

***********************************************************

Euman writes:

I know this isnt the answer to 'controls color change' but instead for
images you
may have in your program.

In an earlier version of my (Euphoria Setup Utility for Programmers) "Eusup"
I used some interesting code snippets to allow the program to be seen the
same in 256 color or higher. (assuming the same palette exist in all images
used)
btw, I still have that code if anyone wants it, email me...

There is alot of work figuring out palette operations so I offer what I
have.

You'll need these:

-- DCstuff
xSaveDC = define_c_func(gdi32, "SaveDC",{C_LONG},C_INT)

-- Palette Manipulation
xCreatePalette = define_c_func(gdi32, "CreatePalette", {C_LONG},C_LONG)
xSelectPalette = define_c_func(gdi32, "SelectPalette", {C_INT, C_INT,
C_INT}, C_UINT)
xRealizePalette = define_c_func(gdi32, "RealizePalette", {C_INT}, C_INT)
xSetPaletteEntries = define_c_func(gdi32, "SetPaletteEntries",{C_LONG,
C_UINT, C_UINT, C_POINTER},C_UINT)

--Winstuff
xInvalidateRect = define_c_func(user32, "InvalidateRect", {C_POINTER,
C_POINTER, C_LONG}, C_LONG)

--Memstuff
xCopyMemory =
define_c_func(kernel32,"RtlMoveMemory",{C_POINTER,C_POINTER,C_LONG},C_LONG)

global procedure pokew(atom addr,object w) -- poke word by Jacques Deschenes
    if atom(w) then
      poke(addr,{remainder(w,256),floor(w/256)})
    else
      for i = 1 to length(w) do
          poke(addr+(i-1)*2,{remainder(w[i],256),floor(w[i]/256)})
      end for
    end if
end procedure

-- (highly modified!) Code from win32lib development
-- "contains palette code and optimizations"
-- Euman 2002

global atom newpal, palinfo
newpal = 0

----------------------------------------------------------------------------
-
function packScanLine( sequence pixels )
    -- convert a scanline of data into a packed scanline
    integer fill
    sequence packed
    packed = pixels
    fill = and_bits( length( packed ), 4 - 1 )
    if fill then
        packed = packed & repeat( 0, 4-fill )
    end if
    return packed
end function

constant CBM_INIT = #4

global atom hPal, ple ple = myalloc(1028)
atom memBitmapInfo

integer pal_exist pal_exist = 0

global sequence spal

global function createDIB(atom hdc, sequence pal, sequence pixels)

    integer palSize, headerSize, bitsPer, h, w, at
    atom memBits, hDIB

    palSize = length(pal)
    bitsPer = 8

    -- size of bitmap
    w = length( pixels[1] )
    h = length( pixels )

       -- calculate the size of the BITMAPINFO header
    headerSize = 40 + (4 * palSize )

       -- Allocate memory for DIB
    memBitmapInfo = allocate(headerSize)

    -- build the bitmap info header
    poke4( memBitmapInfo + 0, 40 )
    poke4( memBitmapInfo + 4, w )      -- Width in pixels.
    poke4( memBitmapInfo + 8, -h )     -- Height in pixels.
    poke ( memBitmapInfo + 12, {1,0} ) -- 1 color plane.
    poke ( memBitmapInfo + 14, {8,0} ) -- bits per pixel.
    poke4( memBitmapInfo + 32, 256 )   -- Colors used.
    poke4( memBitmapInfo + 36, 256 )   -- Colors used.

    for i = 1 to h do
        pixels[i] = packScanLine( pixels[i] )
    end for

    -- get bytes per scanline
    w = length( pixels[1] )

    -- Allocate storage
    memBits = allocate(h * w)

    -- copy pixels to memory
    at = memBits
    for i = 1 to h do
        poke( at, pixels[i] )
        at = at + w
    end for

    at = memBitmapInfo + 40

    if  pal_exist = 0 then
      for i = 1 to 256 do
        poke(at, pal[i])
        at = at + 4
      end for

      pokew(ple + 0, #300)
      pokew(ple + 2, 256)

      junk = c_func(xCopyMemory,{ple+4, at - 1024,  1024})
      newpal = c_func(xCreatePalette,{ple})
      junk = c_func(xSetPaletteEntries, {newpal, 0, 255, ple+4})
      hPal = c_func(xSelectPalette, {hdc, newpal, 1})
      junk = c_func(xRealizePalette, {hdc})
      junk = c_func(xSelectPalette, {hdc, hPal, 1})

      pal_exist = 1

    else
      junk = c_func(xCopyMemory,{at, ple+4, 1024})
    end if

    -- Create the DIB.

    hDIB = c_func( xCreateDIBitmap, {
                        hdc,
                        memBitmapInfo,
                        CBM_INIT,
                        memBits,
                        memBitmapInfo,
                        0} )


     free(memBits)
     free(memBitmapInfo)

     return hDIB
end function

In my "WndProc( )" I use this method to insure that when the app looses then
regains
focus that the palette is automagically returned to show the images as they
were
ment to be seen in the first place.... Hope this crap helps!

    elsif iMsg = WM_ACTIVATE then
          if LOWORD(wParam) =  0 then
              hPal = c_func(xSelectPalette, {hdc, newpal, 0})
              junk = c_func(xRealizePalette, {hdc})
              InvalidateRect(hwnd, NULL, 0)
              savedDC = c_func(xSaveDC,{hdc})
          elsif LOWORD(wParam) =  1 or LOWORD(wParam) =  2 then
                if savedDC > 0 then
                   junk = c_func(xRestoreDC,{hdc, -1})
                   hPal = c_func(xSelectPalette, {hdc, newpal, 0})
                   junk = c_func(xRealizePalette, {hdc})
                   InvalidateRect(hwnd, NULL, 0)
                end if
          end if
          return junk


There is alot more to this than meets the eye but, I give this info to help
save time.
Make sure to DeleteObject's & DeleteDC's or you'll have resources stuck out
there.

Hopefully helpfull,
The Euman

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu