Fixing MenuStrip, part 2: Visible vs. Available, and a repro case

Not all MenuStrips will exhibit the scrolling bug.

In a nutshell: if you ever hide any menu items, you’re living dangerously.

Visible and Available

First, an aside on how you go about hiding menu items.

ToolStripMenuItem has two visibility properties: Visible and Available. They both do the same thing, except when they don’t.

To be more specific, both their setters do the same thing. So if you want to hide a menu item, you can either set Visible to false, or you can set Available to false. Same thing. So why are there two properties for the same thing?

The difference is if you ever want to read the properties, to find out whether the item is already hidden. The Visible getter does not do what you want. Never use it. Reading Visible does not tell you “did I set Visible to true?” No, that’s what Available is for. (Obviously.) No, reading Visible tells you “is the menu currently popped up on the screen?” Which has a usefulness score of somewhere less than or equal to toe fungus.

Summary: always use Available. Never use Visible. The one exception is the form designer — Available isn’t shown in the Property Grid, so there you’re stuck with Visible.

The repro case(s)

Here’s the repro case I’ve been working with. There may be simpler repro cases, but this one is expressive enough to be interesting. Here are the contents of my File menu:

  • New
  • Open
  • Import (hidden)
  • Export (hidden)
  • Exit

If you write some simple code to create a MenuStrip and add those items, you’ll see the bug. If you use the form designer to do the same thing, you won’t see the bug.

That’s because the designer-generated code will instantiate all the menu items, then add them to the File menu’s DropDownItems collection, and then set all the menu items’ properties, including Visible. If you do that, with these five items, no bug. If you set Visible Available to false before adding the items to the menu, you see the bug. Don’t ask me, I didn’t write the buggy code.

However, if you only hide one of the menu items, not both, then you’ll still see the bug even with the designer. In fact, the menu will scroll so far you’ll only see the last item, followed by a whole bunch of white space.

If you show and hide menu items at runtime, you’ll never get back to the “bug with both hidden” state, at least not as far as I’ve been able to tell — that only happens if you hide them before you add them to the menu, and then never touch their Visible Available property again.

But anytime you’re only hiding one of the two — hiding Import and showing Export, or vice versa — you’ve got the bug. Design-time, runtime, whatever.

Simple repro

Create a new project and paste the following code into its Main method.

C#:

var Form = new Form();
var Menu = new MenuStrip();
var File = new ToolStripMenuItem("&File");
File.DropDownItems.AddRange(new[]{
    new ToolStripMenuItem("&New"),
    new ToolStripMenuItem("&Open"),
    new ToolStripMenuItem("&Import") {Available = false},
    new ToolStripMenuItem("&Export") {Available = false},
    new ToolStripMenuItem("E&xit")});
Menu.Items.Add(File);
Form.Controls.Add(Menu);
Form.Show();
Application.Run(Form);

Delphi Prism:

var Form := new Form();
var Menu := new MenuStrip();
var File := new ToolStripMenuItem("&File");
File.DropDownItems.AddRange([
  new ToolStripMenuItem("&New"),
  new ToolStripMenuItem("&Open"),
  new ToolStripMenuItem("&Import", Available := False),
  new ToolStripMenuItem("&Export", Available := False),
  new ToolStripMenuItem("E&xit")]);
Menu.Items.Add(File);
Form.Controls.Add(Menu);
Form.Show();
Application.Run(Form);

Feel free to play around with these. I did a test project with a couple of checkboxes so I could toggle the menu items’ visibility at runtime. It was kind of fun to poke at, but I still have no idea how they got it to screw up the way it does.

What’s next?

Tune in next time for the Microsoft-sanctioned workaround for their bug, and a bit of stumbling since it’s a pretty awful workaround. Hang in there, it’ll get better.

This post is part of the Fixing MenuStrip series.

Fixing MenuStrip, part 1: Introduction and screenshots

In .NET 2.0, Microsoft added MenuStrip and ContextMenuStrip controls to replace the old MainMenu and ContextMenu. The new ones support images next to menu items, edit boxes inside menus, etc. Fairly cool.

However, they’ve got a major bug that Microsoft doesn’t intend to fix. See the screenshot at right. Why the blank space at the bottom of the menu? And more importantly, what happened to the first menu item (the highlighted one) — why is it mostly cut off?

It’s easy to showcase this bug. For that matter, it’s easy to fix. (Why Microsoft can’t figure it out, I don’t know.)

In this “Fixing MenuStrip” series, I’ll demonstrate the problem, and then show how to make a very specific fix for a very specific scenario. From there, I’ll work my way up to progressively more general solutions. By the time I’m done, you’ll be able to fix every menu on the form (including context menus) with one method call.

The coolest thing is that there’s no need to descend from MenuStrip to fix it. You’ll be able to add a line of code saying “And by the way, this menu should support the keyboard,” and it will just start working. It’s basically declarative programming: you declare your intention — “I want my MenuStrip to work” — and somebody else takes over and figures out how to do it. Multicast delegates and lambda expressions FTW!

Along the way, I’ll provide code snippets in both C# and Delphi Prism (aka RemObjects Chrome, aka RemObjects Oxygene — somebody let me know when they stop changing the name). If people ask, I could probably cook up complete project files to download, though I’d rather spend my time writing about the interesting technical stuff. (And besides, my personal computer only has the command-line compiler for Prism, not the IDE, so project files would be a bit of a challenge — the project-file format appears to be undocumented.)

All of my Prism examples will work on .NET 2.0, since my main computer is a Windows 2000 laptop, and .NET 3.x requires XP. My C# examples, especially the later ones, will be for C# 3.0 since I want to use lambdas — I’ll just have to borrow Jennie’s computer when I want to write those articles.

Screenshots of the problem

Let’s start by showcasing the problem. Here are a couple of screenshots from a little sample app I wrote. In both, I’ve got a menu with three visible menu items: “New”, “Open”, and “Exit”. In the left picture, I used the mouse to highlight the “Exit” menu item. In the right one, I used the keyboard’s arrow keys to do the same thing.

The two should look identical. Selecting something with the mouse, selecting something with the keyboard — there’s no reason for those to work differently.

And even apart from that… I mean, just look at it. What the hell? The menu apparently just scrolls its contents up, even though everything fits without scrolling and there are no scroll arrows. It’s obvious that everything fits, because the left screenshot looks great — the selection rectangle isn’t cut off, and the margins are fine.

In this example, everything scrolls by 17 pixels, but that will vary in practice. I’ve seen one — a menu with around 10 or 15 menu items — that scrolled so far that you could only see the bottom half of the last menu item, hanging out there at the top of the menu. The rest of the menu was just blank white space.

So how serious is it?

In their response to the bug report, Microsoft notes that the issue is purely visual, and there’s no functionality loss. You can use the arrow keys to scroll the menu contents back into view.

I contend that that’s a poor excuse for making a crappy design. Little things matter. And Microsoft’s slipshod coding (and testing) makes my programs look like jokes, and me look like an amateur.

And besides, why put up with crappy code, when you can fix it? Tune in next time as I show code that reproduces the problem, and start working on a fix.

This post is part of the Fixing MenuStrip series.

More SmartInspect license WTF

Still reading the SmartInspect license agreement.

Now, it’s normal for a license agreement to, in effect, say “We don’t promise the software actually works”. It’s frightening when you think about it, but it’s become standard operating procedure.

Once again, the overachievers in Gurock’s legal department have taken this concept to dizzying new heights. Either that, or their site has been hacked by an angry mob with torches and pitchforks. Is it seriously possible that a company would publicly hate on their own product this badly?

6.1 When using the licensed programs, in order to avoid damage that may be caused to other programs or stored data being used simultaneously, the Customers shall in good time before using/utilising the licensed programs back up the programs and data involved, and not use programs of this kind in actual operation before he has verified the flawless quality of these programs by a test routine.

(emphasis mine)

That’s copied straight out of the actual SmartInspect license agreement on their actual Web site.

So let me see if I understand this. I am contractually obligated to assume their software is horribly broken, until and unless I am able to form and execute a test plan to prove otherwise. In other words, their entire Quality Assurance department consists of their paying customers.

(I have a hard time believing that that’s actually the case, but that’s certainly the message they’re going to great pains to send.)

Does anyone happen to use CodeSite, and have a copy of their license agreement that they could send me? If so, please get in touch. If Raize actually shows some confidence in their own product, I’d be sorely tempted to return SmartInspect and go with the slightly more expensive, but presumably tested before shipping, competitor.

SmartInspect and the End Usufructuary License Agreement

We just purchased a couple of licenses for Gurock Software’s SmartInspect. I’ve gotten as far as the license agreement.

Their license agreement aspires to dizzying new heights in legalese. Take this sentence, from the third paragraph of Section 1 (Subject-matter of the conditions):

The downloading or delivery of the licensed programs and the granting of usufructuary rights to them shall be explicitly tied to compliance with these General Business and Licensing Conditions.

(emphasis mine)

Usufructuary?!

Turns out it’s an actual word. According to Google’s snippet for the World Wide Words site (but not, oddly enough, according to the World Wide Words site itself):

‘Usufructuary’ is a technical term in law for a person who has the right to enjoy the products of property he does not own.

So, you don’t own the software, but you can still use it and gain the benefit of it. Familiar concept, grotesque word.

As Kyle, one of my co-workers, pointed out, there’s a slightly less obtuse word for that: a user. Perhaps someone should suggest that to Gurock’s lawyers…

Grace

Reverend Stephen’s sermon this morning was, among other things, about grace.

I’ve heard the song “Amazing Grace” many times, and still don’t really understand what it’s talking about. So “grace” has always seemed like this big, mysterious, complicated thing to me. But Stephen presented it at its most basic, where it’s actually quite simple: grace is when you get something that you didn’t deserve.

(He compared it to mercy, which is when you don’t get something that you did deserve. I kind of like that comparison.)

The traditional Christian example of grace would be salvation: you can’t ever earn it; it can only be given as a gift. I lean with the Universalists here — if salvation exists, I think it’s given to everyone, not just to those who are in the club — so I really don’t know how I feel about the “salvation through grace alone” thing.

Stephen’s point was that, as Unitarians, we find grace — in particular, the gift of strength to get us through the hard times — through community. I’m with him on that one. That’s why I’m in covenant groups (and why I’m facilitating a group this year).

But I was still intrigued by this idea of grace, so I started looking around for it today. And I found it. I went outside and saw it in the sunlit trees against the cloudy sky. It was stunning today. I didn’t earn that kind of beauty, but it was there for me nonetheless. It was there for everybody, and it was there for nobody at all, just for its own sake, but it’s inspiring to think that, yes, it was also there for me. Not earned. Freely given.

Later, when I was at my part-time cashiering job (still working on paying down those credit cards!), I was talking to another cashier, a 20-year-old, about what it was like to have been married for 11 years. And I realized (not for the first time) that one of the real gifts I have is a wife who doesn’t expect me to be perfect. She accepts me even with my weaknesses and faults. That’s a tremendous gift. I try to do the same for her — and, of course, neither of us is perfect about it. But this is not something that I ever could have deserved. Love is not earned. It’s freely given. Love is grace.

(I didn’t try to explain all of that to the other cashier. It would have taken far too long to explain the context.)

Later, when I left the store at closing time, I reached into my pocket for my car keys. And they weren’t there. They weren’t in my coat pocket either. I thought, “Okay, I’ll make sure they’re not in the car before I panic.”

I found them sitting on the passenger seat of my car. The car had been sitting there, unlocked, for six hours, with the keys in plain view. And nothing had happened. My car keys, my house keys, not to mention my car, all still there.

I didn’t deserve that. Some days, I might have thought of it as luck. Today? I’m still wondering.

If Nebraska banned affirmative action

One of the issues on Nebraska ballots will be a constitutional amendment to ban affirmative action.

Before I found out more about it, I would’ve been tempted to vote yes on the amendment. After all, affirmative action is all about quotas, and quotas are all about discrimination. Reverse discrimination, after all, is still discrimination.

But after an informational meeting at church recently, I’m set against the amendment. Here are three things whose state funding could be cut off, or at least could be subjected to long, expensive court battles, if the amendment passed:

  • Breast-cancer screenings. Why? Because they’re offered primarily to women, since women get breast cancer 100 times more often than men. And since screenings are offered to women and not to men, that would be considered sex discrimination under the amendment.
  • Domestic violence programs. More women than men are targeted by domestic violence, which is why things like women’s shelters exist. But again, the amendment would consider that discrimination, and the state could no longer provide funding.
  • Outreach programs to encourage minorities to attend college. I’m not even talking about discriminatory scholarships — just outreach programs to get minorities to even think about college as an option.

In each of those, there’s a case to be made that they’re “discriminatory”. And you know what? I don’t care. Any theoretical “bad karma” resulting from their “discrimination” is far outweighed by the real-world good in these programs.

Vote No on Initiative 424.

More information, including the text of the proposed amendment (PDF) and a list of groups opposing Initiative 424, is available at the Nebraskans United Web site.

An hour until NaNo…

I had a long week this afternoon.

And then had to go shopping for Halloween candy, since we had expected to be out of town this weekend, and it turns out we weren’t.

But the upshot is that I’ll be at home for the start of NaNoWriMo, so I can write on my computer instead of on paper. Which is cool. Plus, there’s a handful of Halloween candy left to fuel that first writing session.

An hour to go…

Yet Another Fantasy Gamer Comic

I’ve read several RPG-themed webcomics. My favorite is Adventurers! (yes, the artwork gets better in later strips).

Well, Google Reader‘s Recommendations feature just found me another one: Yet Another Fantasy Gamer Comic. (Caution: includes nudity.)

The artwork is mostly penciled and very rough-draft, but that doesn’t mean it’s not good. Honestly, I like the penciled strips more than the occasional (every 100 strips) color ones. And I love the sense of humor. The goblin dating the beholder, the chimera’s dorky heads, the Spy vs. Spy parodies, the lich king weeding the orc’s garden… classic.

But one of my favorite characters has to be the kobold pirate, Captain Fang. Every line he ever speaks is an utter non sequitur.

This has been a daily strip for over two years, so there’s plenty of archives to dig through. Start at the beginning (not work-safe) and happy reading!

DGrok 0.8.1: multithreading, default options, GPL

Version 0.8.1 of the DGrok Delphi parser and tools are now available for download. Download DGrok 0.8.1 here.

What is DGrok?

DGrok is a set of tools for parsing Delphi source code and telling you stuff about it. Read more about it on the DGrok project page.

What’s new in 0.8.1?

Quick summary of what’s new (more information below):

  • Now GPL-licensed.
  • Reasonable defaults for {$IFOPT}.
  • Multithreaded parser.
  • Less memory usage when parsing twice.
  • Copy tree results to clipboard.

Now GPL-licensed

Prior versions of DGrok used NUnitLite for their unit tests, and therefore had to ship under the same license as NUnitLite: the OSL (Open Software License). I’ve never been happy about that. The world really doesn’t need yet another tiny variation on the GPL, especially when that variation isn’t GPL-compatible.

So for this release, I dumped NUnitLite and switched to NUnit. That let me drop the OSL and switch to an industry-standard open-source license, the GPL (GNU General Public License).

There are a few downsides. NUnit has tremendous overhead; on my laptop, it takes about fifteen seconds just to start the NUnit console runner and load the tests, plus the time to run them (which is also slower than under NUnitLite). It also adds an extra 321 Kb to the download size. And now I have to clutter my test code with a bunch of stupid [Test] attributes.

If I think that’s a good trade, then apparently the OSL annoyed me more than I thought.

Reasonable defaults for “{$IFOPT}”.

An annoyance in previous versions (even to me) was that, if you were parsing code that contained things like {$IFOPT C+}, you would have to switch to DGrok’s “Options” page to tell it which compiler settings it should consider to be “on” and which are “off”. If it hit an {$IFOPT} you hadn’t told it about, it would fail to parse that source file.

In 0.8.1, that’s no longer the case. DGrok knows about the default compiler options in a clean install of Delphi, and by default, it assumes you’re using those options. You can still use the Options page to override those settings one by one (e.g. if you compile with range checking on, and want DGrok to parse code inside your {$IFOPT R+} sections), but it’s no longer necessary to do it for every single option.

If anyone’s curious, here are the settings DGrok uses. I just opened Delphi (actually Turbo Delphi) and pressed Ctrl+O Ctrl+O, which prefixes the current file with all the compiler directives currently in effect. Then I did a bit of testing on the odd cases, like A and Z (which can have numbers in addition to + or -, and which do have numbers when inserted by Ctrl+O Ctrl+O). Here’s what I wound up with:

B-, C+, D+, E-, F-, G+, H+, I+, J-, K-, L+, M-, N+, O+, P+, Q-, R-, S-, T-, U-, V+, W-, X+, Y+, Z-

You may notice that A isn’t listed. A is an oddball case, in that it’s treated as neither on nor off. That is, {$IFOPT A+} and {$IFOPT A-} will both evaluate as “false”. There’s a compelling reason for that: it’s what Delphi does under the default settings! So don’t blame me; I’m just being compatible with the real Delphi compiler.

Multithreaded parser

When you use the DGrok demo app to parse a source tree, it now spins up multiple threads to do the parsing. There’s a setting on the “Options” tab to control how many threads you want it to use.

I actually implemented this a few months back, and since then, it’s occurred to me that I was making the problem too complicated — life would be simpler if I’d just used the ThreadPool, and queued a work item for each file I wanted to parse. Oh well; what’s there seems to work. I’ll probably do the thread-pool thing in the future, though.

Less memory usage when parsing twice

I’m embarrassed by this one. In previous versions, if you clicked “Parse” more than once in the same program run (e.g. if you were tweaking the “Options” to deal with {$IFOPT}s), DGrok would temporarily take twice as much memory as it needed to. That’s because I built the new list, and then stored it in the top-level variable… so the old list (stored in that same variable) was still “live” as far as the GC knew, up until the point when I overwrote its reference at the very end.

It’s better now — it nulls out the reference before it starts parsing, so the old list gets GCed as soon as the new parse run starts allocating gobs of memory. So if you regularly parse a million-line code base (like I do), you’ll notice significantly less thrashing.

Copy tree results to clipboard

Pretty simple. There’s a “Copy” button under the tree that shows the parse results. This is mainly useful when you’ve used DGrok to search for, for example, all the with statements in your code, and now want to copy that list into Excel for easy sorting and printing.

Happy parsing!

Of politics and rock stars

We watched Obama’s acceptance speech last week, and we watched McCain’s acceptance speech tonight.

Obama has been accused of being a “rock star”. So it was interesting to notice that McCain was the one who couldn’t ever get a word in edgewise, because the damn crowd wouldn’t ever stop cheering and applauding and hollering and whistling and chanting “USA! USA! USA!”

For God’s sake, people, shut up and let the man talk.