News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

MyToolstrip: A possible replacement for the Windows toolbar

Started by NoCforMe, November 05, 2023, 11:15:28 AM

Previous topic - Next topic

NoCforMe

I got tired of dealing with the idiosyncrasies, limitations and problems with the Win32 toolbar, so I decided to roll my own. It was a lot of work, but I think it's been worth it.

Note: This is not a finished project! Still under construction. However, this is a working demo that I wanted to get out there so people could play with it and maybe offer some feedback, good or bad. It's actually working well enough for me to put it into one of my programs.

For now I'm just posting this executable. Later I'll be happy to make the full source available for anyone interested. It will be in the form of a single assembly-language module that could be assembled and linked to a program. I could make a DLL later if that seems appropriate.

Anyhow, here's what it's all about:

The toolstrip allows you to put any of several of the standard Windows controls within it, as well as "TS-type" buttons which are basically bitmaps that function as buttons. The standard Windows controls can be any of the following:
  • Standard button
  • Radio buttons
  • Checkbox (also a button)
  • Single-line edit controls
  • Single-line static controls

Actually, there's nothing stopping you from putting any type of Windows control in there, like a listbox, etc. It's just that anything that's taller than a single line won't work very well in a narrow strip. I haven't tried it but I'm sure a combobox would work OK.

You add Windows controls by giving the following info., in a structure (TSELEMENT):
  • The classname of the control type
  • The window styles
  • The control's height
  • The control's ID
  • A pointer to the control's text

Notice that there's no width parameter required: the width of the control is computed for you from the length (GDI length, not # of characters) of the text. I think this is a really nice feature; the controls are automatically sized and spaced in the toolbar. Even if the control has no text displayed--say it's an output field, either a static or edit control--you supply a string of text which is used to size it.

For "TS-type" (non-Windows) buttons, you have to specify:
  • The name of the bitmap file OR the resource ID for embedded resources
  • The height and width of the button **
  • Some flags that control the button's behavior

TS-type buttons can be either individual ones or a group of buttons that behaves like a set of radio buttons; push one and it stays selected, push another and it becomes selected. This works like the BTNS_GROUP style for Windows toolbar buttons. (The demo has two groups of buttons so you can see how they operate.)

** I'm going to change this so the actual size of the bitmap is used to size it.

You can also add tooltips, as in the demo. These took a hell of a lot of work to get working as well as they do, which isn't perfect. But I must say it's a hell of a lot better than the Windows tooltips. I remember Steve (Hutch) used to rail against Win32 tooltips; he hated them, and for good reason. They're super-flaky! At first I tried to implement them using the recommended interface, which is to use TrackMouseEvent() to tell when the user hovers over a control with the mouse. I got this to work fairly well, but it was very unreliable: often you could move the mouse over a button and nothing would happen, or it would take f-o-r-e-v-e-r for the WM_MOUSEHOVER message to arrive so you could put up your tooltip.

I just gave up on that method (I still use TrackMouseEvent() to give me a WM_MOUSELEAVE message so I can know when the user has moved off a button, at which point I get rid of the tooltip windows). My method is so much simpler, and it seems to work OK (well, about 98% of the time): I simply look at all WM_MOUSEMOVE messages coming from my buttons and do hit tests on them to figure out when the mouse pointer is over one of them. If that happens, I put up the tooltip windows. (There are actually 2 windows, the little box with text in it and an underlying "shadow" window just for looks.)

I found in working on this that a lot of the work is just finessing stuff to make it work smoothly. Now, my method, being simpler than Windows, lacks some of the fine points, like a short delay in putting up the tooltip, but overall it's just so much more reliable. I never miss a tooltip. There are some cases where the tooltip stays up when it shouldn't (and I would really like to hear from you if you find this happening in any specific way). But even this isn't a show-stopper, just a minor annoyance. I found that adding a 50mS delay after creating the windows eliminated a lot of display problems, like a jittery oscillation if you landed between two buttons. There are a lot of similar tweaks in the code, mostly small positioning adjustments.

I checked, and there are no leaks, at least no GDI leaks. Shouldn't be any memory leaks either since I'm not allocating any memory here.

The box in the middle shows another toolstrip, this one vertical and sized to its contents. I don't have all the vertical-toolstrip stuff functional yet, but they do work.

Coding to use my toolstrips take a bit more work on the data side, not much, but you have to fill in a TSELEMENT structure for each button. Instead of having all the bitmap buttons in a strip like Win32 does, each button here is an individual bitmap, so there's a little more overhead, but not much. You don't have to send any special message to load the bitmaps: that's done automagically through the element list when you call the toolstrip-element creation function, CreateToolstripContent(). Oh, and notice that I can handle bitmap buttons that aren't square (what a concept!).

Anyhow, play with it and let me know what you think.
Assembly language programming should be fun. That's why I do it.

Biterider

Hi NoCforMe
I gave it a quick shot. Nice project!  :thup:
What is your motivation? Is the MS control not good enough?

When running, I noticed 2 things.
First, an intense flickering when moving the mouse. 
The other one is more of a cosmetic issue. When a tooltip is displayed and you move the main window, the tooltip stays where it is. A more consistent behaviour would be to hide it immediately when the parent window changes position.

Regards, Biterider

NoCforMe

Quote from: Biterider on November 05, 2023, 05:43:14 PMHi NoCforMe
I gave it a quick shot. Nice project!  :thup:
What is your motivation? Is the MS control not good enough?

Well, as I said, the MS toolbar has problems and limitations. Plus it's a pain in the ass to program. This version is more flexible in some ways.

QuoteWhen running, I noticed 2 things.
First, an intense flickering when moving the mouse.
The other one is more of a cosmetic issue. When a tooltip is displayed and you move the main window, the tooltip stays where it is. A more consistent behaviour would be to hide it immediately when the parent window changes position.

Yes, I just discovered that myself. Your reply gives me an idea of how to fix it, maybe: destroy the tooltip windows upon receipt of a WM_MOVE message. (BTW, the fact that you were able to move the window with the tooltip visible shouldn't have been possible: they're supposed to go away as soon as the mouse moves away from the button that triggered the tooltip in the first place.)

Flickering? That's not good. I don't see any myself. What OS are you using?

I do see times when the tooltips stay up even after mousing away from the button that brought them up, which isn't right. Still working on it.
Assembly language programming should be fun. That's why I do it.

Biterider

Quote from: NoCforMe on November 05, 2023, 06:18:32 PMFlickering? That's not good. I don't see any myself. What OS are you using?
Windows 10 Home, 22H2

Regards, Biterider

jj2007

Looks good :thumbsup:

A bit of flicker here on Win7-64, but nothing to worry about. Tooltips look non-standard, I have not yet decided whether I like it or no.

No source yet, ok, but let me ask: what's the interface for designing the toolbar? Something like the Excel table in the editor thread, 7 years ago?

> I remember Steve (Hutch) used to rail against Win32 tooltips; he hated them, and for good reason
Yes, in that same thread Steve argued quite a bit ;-)

TimoVJL

May the source be with you

jj2007

I use TLPEView often, Timo. How did you insert the menu into the toolbar?

TimoVJL

#7
My bad, wrong example code.
EDIT: TBMenu code
May the source be with you

jj2007

Quote from: TimoVJL on November 05, 2023, 09:46:59 PMShort example:

We are talking about different things:
- to the left, TLPEView opens a standard menu when hovering over the toolbar - the menu is integrated;
- to the right, what you posted right now: a menu above the toolbar; and it opens only when you click on it.

I'd like to know how you did version 1 - I like it :thumbsup:

jj2007


NoCforMe

Well, what can I say? My wheels grind slow, but they grind fine.

So about that flickering (which I now see, when I move the mouse rapidly over the toolstrip): I'm pretty sure I know why it happens. Don't know how to fix it, though. Here's what's happening:

When I create those 2 little tooltip windows, they become activated, meaning that the windows behind them--the main application window and its contents--become deactivated, meaning their borders get repainted and all that. Which I don't want.

I tried using WS_EX_NOACTIVATE when creating the tooltip windows: that doesn't work. Tried using SWP_NOACTIVATE with SetWindowPos() when I resize and reposition these windows: that has no effect either.

The one thing that did work was to put a WM_ACTIVATE handler in the tooltip window proc:
    CMP    uMsg, WM_ACTIVATE
    JE    do_activate
.....
do_activate:
    CMP    WORD PTR wParam, WA_INACTIVE
    JE    dodefault
    INVOKE    SetActiveWindow, lParam
    XOR    EAX, EAX
    RET

so that every time the tooltip windows get activated, they turn right around and re-activate the previously-activated window (the one whose handle is in lParam). It works, but I'm pretty sure that's where all that flicker is coming from.

I did a pretty extensive online search for solutions to this problem, on StackOverflow and friends; found a lot of discussions of it, but no real definitive solutions.

Does anyone here know how I can create a window and not have it take over activation?

All this makes me jealous of MS developers, who have access to all the hidden innards of the OS and can easily solve problems like this with all kinds of undocumented stuff. Us peons on the outside have to root around in the published interfaces for work-arounds ...
Assembly language programming should be fun. That's why I do it.

NoCforMe

Quote from: jj2007 on November 05, 2023, 08:21:17 PMA bit of flicker here on Win7-64, but nothing to worry about. Tooltips look non-standard, I have not yet decided whether I like it or no.
Please do let me know the verdict. I'm interested in people's reactions to this admittedly non-standard control.
QuoteNo source yet, ok, but let me ask: what's the interface for designing the toolbar? Something like the Excel table in the editor thread, 7 years ago?
Interface? Interface? We don't need no steenkin' interface!

No design interface; the toolstrips are constructed with an array of structures:
TSELEMENT <$tsBtnGroup, 0, 0, $mainTsTsBtnWidth, $mainTsTsBtnHeight, $TBbutton1, 500, Btn1text>
TSELEMENT <$tsBtnGroup, 0, 0, $mainTsTsBtnWidth, $mainTsTsBtnHeight, $TBbutton2, 501, Btn2text>
TSELEMENT <$tsBtnGroup, 0, 0, $mainTsTsBtnWidth, $mainTsTsBtnHeight, $TBbutton3, 502, Btn3text>
TSELEMENT <$tsSep>
TSELEMENT <$tsButton, 0, 0, $mainTsTsBtnWidth, $mainTsTsBtnHeight, $TBbutton4, 501, Btn4text>
TSELEMENT <$tsSep>
TSELEMENT <$tsBtnGroup, 0, 0, $mainTsTsBtnWidth, 14, $TBbutton5, 503, Btn5text>
TSELEMENT <$tsBtnGroup, 0, 0, $mainTsTsBtnWidth, 14, $TBbutton6, 504, Btn6text>
TSELEMENT <$tsBtnGroup, 0, 0, 24, 14, $TBbutton7, 505, Btn8text>
TSELEMENT <$tsSep>
TSELEMENT <0,        ButtonClassname, $buttonStyles, BTNxtext, $mainTsBtnHeight, $TBbutton8, 0, Btn9text>
TSELEMENT <$tsNoText,    StaticClassname, $staticStyles, ST1OutputText, $tsStaticHeight, $ST2>
    DD -1
I've set up all the colors, line widths, element spacing, etc., by hand using EQUates:
$tsElementSpacing EQU 2
$tsButtonSpacing EQU 4
$TSbtnBtnOffset EQU 4
$TSselBoxMargin EQU 2
$tsVelementSpacing EQU 1
$tsElementPadding EQU 6
$tsSepWidth EQU 4
$tsSepHeight EQU 3
$tsStaticHeight EQU 14
$tsEditHeight EQU 18
$tsBtnPushedXoffset EQU 1
$tsBtnPushedYoffset EQU 1
$tsCheckboxAddon EQU 16
$tsSepPenWidth EQU 1
$tsSepPenHlWidth EQU 1
$tsSepPenColor EQU $colorGray
$tsSepPenHlColor EQU $colorWhite
$tsBackgroundColor EQU $colorVltBlue

Source coming soon, after some dust settles ...
Assembly language programming should be fun. That's why I do it.

Greenhorn

Quote from: jj2007 on November 05, 2023, 10:10:42 PM
Quote from: TimoVJL on November 05, 2023, 09:46:59 PMShort example:

We are talking about different things:
- to the left, TLPEView opens a standard menu when hovering over the toolbar - the menu is integrated;
- to the right, what you posted right now: a menu above the toolbar; and it opens only when you click on it.

I'd like to know how you did version 1 - I like it :thumbsup:

How to Create an Internet Explorer-Style Menu Bar
Kole Feut un Nordenwind gift en krusen Büdel un en lütten Pint.

Greenhorn

QuoteI got tired of dealing with the idiosyncrasies, limitations and problems with the Win32 toolbar, so I decided to roll my own. It was a lot of work, but I think it's been worth it.

Looks good.
I did a similar project a while ago, a clone of the Ms Office 2003 Commandbars.

And yes, if you want to implement it properly it's a lot of work and headaches.
Kole Feut un Nordenwind gift en krusen Büdel un en lütten Pint.

jj2007

Quote from: Greenhorn on November 06, 2023, 07:39:45 AMHow to Create an Internet Explorer-Style Menu Bar

Interesting, thanks, but not what Timo did in his TLPEView, where the menu is at the same level as the toolbar, not above. It seems, though, that there are two toolbars displayed, so maybe it can work. The M$ site does not give an example, unfortunately. This will require some time and effort...