Rusty Windows

I’m a little rusty in developing for Windows (like pre 2006). Anyhow, I’m running into a few issues that I’d like to see if there is a better way of doing it.

#1 System colors: GetSysColor doesn’t seem to be returning the actual colors, COLOR_BTNFACE returns white, where as it should return the button face color?? I’ve looked to see if there is a modern replacement, and everything I find online is for .NET if some XML kind of thing. I’ve also tracked down WFS, but was disappointed to see that it’s also using GetSysColor.

#2 I’m trying to create a custom window, and I’m using some example code I’ve found online. However it’s very slow. Does anyone know of any faster code?

[code] #If TargetWin32 then
Declare Function CreateRectRgn Lib “gdi32” (Left As Integer, top As Integer, Right As Integer, bottom As Integer) As Integer
Declare Function CombineRgn Lib “gdi32” (rgnDest As Integer, rgnSrc1 As Integer, rgnSrc2 As Integer, combineMode As Integer) As Integer
Declare Function DeleteObject Lib “gdi32” (hObject As Integer) As Integer
Declare Function SetWindowRgn Lib “user32” (hWnd As Integer, hRgn As Integer, bRedraw As Boolean) As Integer

Dim x, x2, y, w, h, r1, r2 As Integer

r1 = CreateRectRgn( 0, 0, 0, 0 )

h = pic.height -1
w = pic.width -1

For y = 0 To h
  x = 0
  While x < pic.Width
    If pic.Graphics.Pixel(x, y) <> transparentColor Then
      For x2 = x To w
        If pic.Graphics.Pixel(x2, y) = transparentColor Then Exit
        
        r2 = CreateRectRgn(x, y, x2+1, y+1)
        call CombineRgn(r1, r1, r2, 2)
        call deleteObject(r2)
        x = x2
      Next
    End If
    x = x + 1
  Wend
Next
call SetWindowRgn( Handle, r1, True )

#EndIf[/code]

#3 I’m having trouble tracking some code Windows API for visual things, any pointers? Especially to get the more modern styles?

Hello Sam,

Check this: https://dl.dropboxusercontent.com/u/3800071/Forums/CustomShapeWindow.xojo_binary_project

I have no idea about the colors. I am curious about your third question, what do you mean by “more modern styles”, Metro?

Julen

warning: this is definitely a personal opinion based on pyrely personal preference: He is referring to the ugly, unusable flat Crayola-like interface that is now prevalent with Windows 8. We are going back to VGA and 16 colors with Metro (Microsoft really prefers we do not call Metro, Metro. ) :wink:

The only way I found to improve the speed is for cases when you know the window shape is “solid” for the entire width. That is, as you go along a row looking at transparency, the window doesn’t switch back and forth going from solid to transparent, back to solid. The row starts transparent, switches to solid, then back to transparent…that’s it. It works well for things like roundrect (or a roundrect with a pointer, like a popup window, which is what I’ve started using this routine for).

    r1 = CreateRectRgn(0, 0, 0, 0)
    dim picHeight as Integer = pic.Height
    dim picWidth as Integer = pic.Width
    For y = 1 To picHeight
      
      startX = 0
      for x = 1 to picWidth
        if pic.Graphics.Pixel(x, y) <> transparentColor then
          startX = x
          exit for
        end if
      next x
      
      endX = 0
      for x = picWidth DownTo 1
        if pic.Graphics.Pixel(x,y) <> transparentColor then
          endX = x
          exit for
        end if
      next x
      
      if startX < endX then
        r2 = CreateRectRgn(startx, y, endX, y+1)
        i = CombineRgn(r1,r1,r2,2)
        i = DeleteObject(r2)
      end if
      
    Next
    
    i = SetWindowRgn(Handle, r1, True)

For the typical case I have, your method (which is from the Xojo example) takes almost 5 seconds, my method takes about 0.15 seconds. Still longer than I’d like, but way better than before.

But like I said, it only works for “solid” shapes - circles, roundrects, roundrects with pointers are fine. Anything with a hole in the middle of it, or a concave outline, won’t work right.

Crud, can’t edit even after refreshing. I meant to point out why it’s faster - it starts at the left edge and goes to the right until it finds a non-transparent pixel. Then, instead of continuing along the line looking at each pixel, it starts at the right edge and moves left until it finds a non-transparent pixel. It then does a CreateRectRgn based on the start and end values there, rather than a CreateRectRgn for each individual pixel (like your code). That’s why anything with a hole in it will get messed up.

try using uint32 rather than integer in your declares… I’ve seen trouble with the win32 apis where integer doesn’t work.

Windows Store apps, as they call these, are an amazing piece of manure : single screen and no more windows. Why is it still called ‘Windows’ is an insult to logic. Looks like Dos based programs from the 80’s, including crude square buttons as they used to be made with semi-graphics. And on the programming side, a nightmare apparently created as quick and dirty tool for morons, rather than anything meant to facilitate port of existing applications.

Problem is, Microsoft seems intent on having that mess generalized to the detriment of the gigantic Desktop programs installed base. And the aesthetics or lack thereof tends to spread amongst new desktop apps.

I have ported a half dozen of my font programs under the crooked auspices of the Windows Store. Sales are anecdotic.

Not sure the Redmont giant still has the touch. If they wanted to sink their Titanic, they would not act otherwise. But maybe what they really want is sell phones, and no longer an OS ?

Hi Julen, thanks for the newer code. I’ll test it out later today.

I want to provide custom interface elements, but created with the visual styles. I can find .net code to do this, but I understand that .Net is a .No directly through Xojo (currently).

Also, all the MHIG I can find refers to the ‘Metro’ (but don’t call it that) style. It seems that they’re trying their hardest to get devs to build apps this way. Don’t get me wrong it’s nice, but you’ve got two platforms here and dumping the one that makes you money isn’t very smart IMHO.

Ha!

Custom shaped windows demo is included with Xojo Sample code…also shows how to use aero styles.

Thanks Matthew,
The custom window shapes is the same code that I had before (which is slow), I’ll check out the Aero example later today.

Just a thought, not tested : create all your windows as invisible on launch, and then turn them visible when needed. Would that not speed things up ?

[quote=87071:@Sam Rowlands]Thanks Matthew,
The custom window shapes is the same code that I had before (which is slow), I’ll check out the Aero example later today.[/quote]

The part that is slowing your program down is the create region api. At load, it is literally going pixel by pixel of your window to create a “map” which gets painted over the window to give it a custom shape. In other languages the best practice is to build this map during designtime and perhaps save it to file where it can be saved into your program as a string constant that can be converted to a memoryblock at runtime. Then, comment out the create region api and replace it with a loadmap function(see windows api GetRegionData). All Windows controls are considered “windows” (buttons textfields etc) which is why they are created with an api as such “CreateWindowEx (0,“BUTTON”,0,“CAPTION”,…)”. (Even Xojo does that under the hood :-)) creating regions began as an api for custom shaped controls and originally was never applied to “actual Windows” until WMP (Windows media player), but since it works on any windows class object, even the standard “window” applies. Using GetRegionData after a static map has been created will make the process instantaneous :slight_smile:

Thanks Matthew…
Unfortunately the actual shape is generated at runtime, (I could generate all possibilities I guess) however if the data is a simple memory block, perhaps theres a faster way of converting an image to the data? After all, it’s simply creating a binary mask right?

hmmm…

Its a mask in “windows sense” of coordinates…created pixel by pixel as

x,y x+1,y x+2,y till then end of the width then
x,y+1 x+1,y+1 x+2,y+1

And so on until every pixel has been gone through…its not a mask in xojo terms, rather a set of coordinates in a buffer that tells Windows to “neglect” When it paints the window… And only of “a certain color”… so if you’re generating the region data multiple times it will take quite a while. Unfortunately there is no way too run a function against say…RGBSurface :-/ the best speed you’ll get is if you write a c/c++ library and invoke it yourself through declares

Sam - did you try my code, or is your shape too irregular?

Hi,

I would also like to know whether the project I posted is what you are looking for or I misunderstood your request. :slight_smile:

I didn’t realize you wanted to change the shape of the window at runtime. I added a second custom shape to the previous project and the code to switch between the two. If you don’t know the shape beforehand you can create the corresponding binary image. Here is the project (I believe the previous link should also lead to the updated project, but just in case): https://dl.dropboxusercontent.com/u/3800071/Forums/CustomShapeWindow.xojo_binary_project

If I have some time, I would like to add some transparecy gradient to the border of the custom shaped window because as it is right now it’s not smooth. I will have to find the required api calls and translate them to Xojo, though.

Julen

A little update in my demo project: I have added some comments and also I have made the color of the displayed window match that of the system (it does match the system color in my computer but, although I am querying the system for the color, I don’t know what will happen if another theme is set).

Hi Julen - thank you for your sample. I think with a little work I’ll be able to use it instead of what I’m currently doing. A couple of notes (for anyone trying to use this as their solution):

  1. If you use white as the transparent color, textfields (and presumably text areas, etc) are unusable because of their white background. They just show up clear on the inside and you can’t click in them, you end up clicking whatever’s behind them. To solve this, I made the background of my shape red, the window fill red, and changed the transparent color to red as well.

  2. Instead of using WS_BORDER, which gives a thin border, I prefer no border at all. To do this, use this instead:

WS_NOBORDER = GetWindowLong(me.Handle, GWL_EXSTYLE) and not WS_CAPTION and not WS_THICKFRAME and not WS_MINIMIZE and not WS_MAXIMIZE and WS_SYSMENU

call setwindowlong (me.Handle, GWL_STYLE, WS_NOBORDER)
  1. Instead of maximizing the window in the Paint event, I want to leave the window the same size as designed. I replaced your SetWindowPos code in the Open event with the following, using the Width and Height of the window instead of 0,0:
call SetWindowPos(me.WinHWND, 0, 0, 0, Width, Height, SWP_FRAMECHANGED)

I haven’t actually incorporated it into my popover window code yet, but it works well with a saved bmp so it should work well with one I’m creating on the fly…

Bill

Great, thanks Bill for sharing the improvements. I am not using this in any project (I only generate apps to help me at work) so I will probably never use it myself, but I like trying and learning new stuff.

Yes, white was probably not the best choice, :slight_smile:

Julen

Oops, I forgot the definitions of some of the constants for removing the border:

    Const WS_BORDER = &H800000
    Const WS_CAPTION = &HC00000
    Const WS_THICKFRAME = &H40000
    Const WS_MINIMIZE = &H20000000
    Const WS_MAXIMIZE = &H1000000