[comp.sys.mac.programmer] Append menu is slow.

dudek@ai.toronto.edu (Gregory Dudek) (05/10/89)

The application I am writing needs to create some large menus; up to
128 items (sometimes more).  I know, that's uuuugly but I want to
allow selection from a long list of undifferentiated items.  

  I am using AppendMenu to make some big menus and it is slowwwwww (i.e. on
the order of 5 seconds on a Mac Plus).  Worse yet, I have to create 
new menus like this dynamically & the delays are unbearable.  If 
anybody has any suggestions on how to speed things up, they'd be 
most welcome.
  I am pretty sure AppendMenu must re-scan the menu serially each time
a new item is inserted.  With this in mind, I tried using InsertItem
but it's just as slow.  While we're at it, inserting several items at a
time using the semicolon as a separator doesn't help either.

  (Yes, I can use a scrolling list instead of a huge menu, but I am
  not at all sure that's any more convenient.  Such a list is essentially
  the same as a menu & have a lot of them floating around the screen could
  be a real pain.)

  Gregory Dudek
-- 
Dept. of Computer Science (vision group)    University of Toronto
Nice mailers:  dudek@ai.utoronto.ca
UUCP: {uunet,decvax,linus,pyramid,
		dalcs,watmath,garfield,ubc-vision,calgary}!utai!dudek
ARPA: user%ai.toronto.edu@relay.cs.net

oster@dewey.soe.berkeley.edu (David Phillip Oster) (05/10/89)

In article <89May9.171757edt.11077@ephemeral.ai.toronto.edu> dudek@ai.toronto.edu (Gregory Dudek) writes:
>  I am using AppendMenu to make some big menus and it is slowwwwww (i.e. on
>the order of 5 seconds on a Mac Plus).

AppendMenu doesn't know that you are going to be calling it again
immediately, so it calls CalcMenuSize(), which does a linear scan over
the menu to see how wide the menu should be by doing a StringWidth() on
each item.

The structure of menus is documented in Inside Mac. Menu items are
basically pascal strings followed by four bytes of extra information. At
the end of the muenu is a null byte.  You can use Munger to insert items
into a menu, then call CalcMenuSize() yourself after you are all done.

If you are really paranoid, you can copy and renumber the current menu
definition procedure and set up your menu to use it. That will guarantee
that if Apple ever changes the format of standard menus, and the MDEF to
run them, that your menus will still work.  I think this is over-paranoia
myself.

trebor@biar.UUCP (Robert J Woodhead) (05/10/89)

In article <89May9.171757edt.11077@ephemeral.ai.toronto.edu> dudek@ai.toronto.edu (Gregory Dudek) writes:
>The application I am writing needs to create some large menus; up to
>128 items (sometimes more).  I know, that's uuuugly but I want to
>allow selection from a long list of undifferentiated items.  

DO NOT USE MENUS IN THIS WAY.  It is contrary to the spirit of the Mac
user interface.  Use a scrolling list instead, for several reasons:

	* It is more efficient, and faster.
	* It allows use of the scrolling metaphor users are accustomed
	  to, rather than the hacked up menu scrolling.
	* Scroll bars let you scroll a "page" at a time.
	* You can implement keyboard equivalents (ala Resedit).
	* You can give the user control over size and position of the
	  list.

Quite frankly, the fact that you are having this problem indicates that
your user interface requires serious rethinking.  A huge list of
undifferentiated items is a perfect example of what a user should NEVER
be faced with, because he/she will never be able to find the thing they
want when they want it.  If possible, menus should have <10-15 items.

-- 
Robert J Woodhead, Biar Games, Inc.  !uunet!biar!trebor | trebor@biar.UUCP
"The lamb will lie down with the lion, but the lamb won't get much sleep."
     -- Woody Allen.

keith@Apple.COM (Keith Rollin) (05/10/89)

In article <29122@ucbvax.BERKELEY.EDU> oster@dewey.soe.berkeley.edu.UUCP (David Phillip Oster) writes:
>In article <89May9.171757edt.11077@ephemeral.ai.toronto.edu> dudek@ai.toronto.edu (Gregory Dudek) writes:
>>  I am using AppendMenu to make some big menus and it is slowwwwww (i.e. on
>>the order of 5 seconds on a Mac Plus).
>
>The structure of menus is documented in Inside Mac. Menu items are
>basically pascal strings followed by four bytes of extra information. At
>the end of the muenu is a null byte.  You can use Munger to insert items
>into a menu, then call CalcMenuSize() yourself after you are all done.
>
>If you are really paranoid, you can copy and renumber the current menu
>definition procedure and set up your menu to use it. That will guarantee
>that if Apple ever changes the format of standard menus, and the MDEF to
>run them, that your menus will still work.  I think this is over-paranoia
>myself.

I don't. I think that what you suggest is very bad. Sure, the Menu Manager data
structures are documented, but...

Inside Mac V, page 228:

	"WARNING: The MenuList data structure is listed for information only;
	 	  applications should never access it directly."

Inside Mac V, page 230:

	"WARNING: The MenuInfo data structure is listed for information only;
		  applications should never access it directly. This structure
		  is not a valid Pascal type because of its dynamic size; it's
		  shown for conceptual purposes only."

That's enough warning to make _ME_ paranoid. However, there is one other little
facet of this whole situation that would make me shiver under my bed. Check 
out Technote #227: "Toolbox Karma." That's the one that talks about not
depending on internal data structures. 

It's also written by the guy who is working on the Menu Manager...
------------------------------------------------------------------------------
Keith Rollin  ---  Apple Computer, Inc.  ---  Developer Technical Support
INTERNET: keith@apple.com
    UUCP: {decwrl, hoptoad, nsc, sun, amdahl}!apple!keith
"Argue for your Apple, and sure enough, it's yours" - Keith Rollin, Contusions

dudek@ai.toronto.edu (Gregory Dudek) (05/10/89)

Context:
>>The application I am writing needs to create some large menus; up to
>>128 items (sometimes more).  I know, that's uuuugly but I want to
>>allow selection from a long list of undifferentiated items.  

In article <554@biar.UUCP> trebor@biar.UUCP (Robert J Woodhead) writes:
>
>DO NOT USE MENUS IN THIS WAY.  It is contrary to the spirit of the Mac
>user interface.  Use a scrolling list instead, for several reasons:
>
    [some good reasons, not all of which apply to my case, deleted]
>
>Quite frankly, the fact that you are having this problem indicates that
>your user interface requires serious rethinking.  A huge list of
>undifferentiated items is a perfect example of what a user should NEVER
>be faced with, because he/she will never be able to find the thing they
>want when they want it.  If possible, menus should have <10-15 items.
>

  (Long response & justification follows...)

  This is the kind of religious dogma that keeps coming up here.
    "you are doing a bad thing.  It's against the guidelines!  It's against
    the law!  Open your eyes!"

  Sure, pointing out the potential problems with an approach may be useful.
Yes, of course I know that large menus have problems associated with 
them.  Maybe you should consider the possibility that I have a problem you 
may not have encountered before, and that this solution is might be 
appropriate in this context (despite its apparent ugliness).

   Basically, I want to be able to select items from large groups of
user-defined objects.  The objects aren't graphic and the semantics 
of the objects aren't known to the program (they are created outside 
the program).  
   This kind of situation arises in programs that support large numbers of 
user-defined macros.  It is often difficult to structure the available macros
except in a long list (either that, or FORCE the user to structure them - a bit
fascistic).
  Worse yet, in my case I may have a whole bunch of such lists.  I am
using popup menus for them.  At least they popup with the currently 
selected parameter value under the mouse.  The problem is that creating them
dynamically is to slow.

    An analogy might be drawn to a utility for manipulating different 
groups of files.  The finder does it by having lists of files pop up when 
you open a folder.  This metaphor works well when you're staying in 
one open folder for a while.  When you want to pick a file here & a file
there (or in may case, set a parameter here, a parameter there) the 
desirability of having all those overlapping lists becomes questionable.

   Since the item-lists have no structure I know of, no hierarchical
decomposition can be used.
   In short, I (still) need long popup lists that allow you to
make a quick choice, then they dissapear.  Sure sounds a lot like a
popup menu.

   My apologies for the length of this reply, but I wanted to try and
make my point fully & avoid further scolding.

   Greg Dudek
-- 
Dept. of Computer Science (vision group)    University of Toronto
Nice mailers:  dudek@ai.utoronto.ca
UUCP: {uunet,decvax,linus,pyramid,
		dalcs,watmath,garfield,ubc-vision,calgary}!utai!dudek
ARPA: user%ai.toronto.edu@relay.cs.net

lsr@Apple.COM (Larry Rosenstein) (05/11/89)

In article <29122@ucbvax.BERKELEY.EDU> oster@dewey.soe.berkeley.edu (David 
Phillip Oster) writes:
> AppendMenu doesn't know that you are going to be calling it again
> immediately, so it calls CalcMenuSize(), which does a linear scan over
> the menu to see how wide the menu should be by doing a StringWidth() on
> each item.

That is likely the problem.

> the end of the muenu is a null byte.  You can use Munger to insert items
> into a menu, then call CalcMenuSize() yourself after you are all done.

A better approach (one used in MacApp) is to temporarily replace the menu 
defproc handle in the menu with a handle to a dummy defproc that does'nt 
do anything for calculating the menu size.  Then call the normal Menu 
Manager routines to add the menus, restore the defproc handle, and call 
CalcMenuSize manually.   This doesn't require that you parse or rely on 
the format of a menu.

Be sure to create a real handle, and put a 6-byte JMP instruction in it.  
Alternatively, you could compile a dummy MDEF and put the MDEF resource 
into your application.


Larry Rosenstein, Apple Computer, Inc.
Object Specialist

Internet: lsr@Apple.com   UUCP: {nsc, sun}!apple!lsr
AppleLink: Rosenstein1

res12@snoopy.UMD.EDU (Matthew T. Russotto) (05/11/89)

In article <30414@apple.Apple.COM> keith@Apple.COM (Keith Rollin) writes:
>In article <29122@ucbvax.BERKELEY.EDU> oster@dewey.soe.berkeley.edu.UUCP (David Phillip Oster) writes:
>>In article <89May9.171757edt.11077@ephemeral.ai.toronto.edu> dudek@ai.toronto.edu (Gregory Dudek) writes:
>>>  I am using AppendMenu to make some big menus and it is slowwwwww (i.e. on
>>>the order of 5 seconds on a Mac Plus).
>> [suggestion on how to low-level hack it deleted]
>[lots of paranoia inspiring info deleted]
>That's enough warning to make _ME_ paranoid. However, there is one other little
>facet of this whole situation that would make me shiver under my bed. Check 
>out Technote #227: "Toolbox Karma." That's the one that talks about not
>depending on internal data structures. 
>
>It's also written by the guy who is working on the Menu Manager...
>--
>Keith Rollin  ---  Apple Computer, Inc.  ---  Developer Technical Support
>INTERNET: keith@apple.com
>    UUCP: {decwrl, hoptoad, nsc, sun, amdahl}!apple!keith

So, how do we avoid the overhead caused by CalcMenuSize? I know of one
way:  Patch CalcMenuSize to do nothing before all the appends, and patch
it back before the last append.  But patching traps isn't my favorite thing
to do either.

-- 
DISCLAIMER:  Not only does the University not share my opinions,
             they don't want me sharing my opinions.
                "This 'Pnews', what does it do?"
             Matthew T. Russotto
	     res12@snoopy.umd.edu (this semester only)

jamesm@sco.COM (James M. Moore) (05/11/89)

In article <89May9.171757edt.11077@ephemeral.ai.toronto.edu> dudek@ai.toronto.edu (Gregory Dudek) writes:
>  I am using AppendMenu to make some big menus and it is slowwwwww (i.e. on
>the order of 5 seconds on a Mac Plus).  Worse yet, I have to create 
>new menus like this dynamically & the delays are unbearable.  If 
>anybody has any suggestions on how to speed things up, they'd be 
>most welcome.

This sounds ugly too but it might be faster:  build your own MENU
resource by hand, and then add it with NewMenu.  MENU resources aren't
all that complex, just the text of the menu items and the modifiers,
and this shouldn't break compatibility, because you'd be using the
published format of a resource.  I just don't know how much speed this
buys you.  (And I've never tried it myself, so I might be missing
something really obviously wrong...)



-- 

		James Moore
			jamesm@sco.com

ksitze@nmsu.edu (Kevin Sitze) (05/11/89)

James,

There's only really one major problem with using a menu for this.
(don't spout off that a menu is the ONLY way to go, because it isn't)
Scrolling in menus is VERY TEDIOUS to the user, because menus have a
bad tendency to scroll only one item at a time.  And if what you say
about the size of the menus (up to 128 items) the wait is especially
bad.  If I had to sit around & wait for several dozen items to scroll
past, my patience level with the offending program is very likely to
plummet to the deepest levels of hell very quickly.  I _don't_ like to
wait 30-45 seconds to make one menu selection.  Believe me, I have
some experience here.  I have a large number of fonts installed on my
machine & I love Microsoft Word 3.0 because of it's scrollable font
selection window. MacWrite bites the big one here (& other areas as
well but I keep it around 'cause Mac TN's are written in MacWrite
format...).

I'd suggest that you implement the selection as follows:

Just create a normal menu item (non-heiarchial) that, when selected,
pops up a dialog box with a scrollable window inside.  (Or even just
create a window that the user can keep around for later use so (s)he
doesn't have to keep selecting a menu item to make a selection.)  Sort
the list alphabetically (if feasable) and make alphabetic keys scroll
to the proper name in the list (Look at the Apple SFGetFile dialog box
and what it does on keypresses.)

If you really need to use menus (for some unknown and ungodly reason)
I suggest that you limit the choices & put only a scarce scattering of
selections (what you or your program deems the most important ones,
it's up to how you want to select the items (e.g. by most recent use,
one for each letter in the alphabet, etc.)) into the actual menu & have
another selection method available as outlined in the paragraph above.

A really great example of what I talked about is (again) Microsoft
Word 3.0.  The only problem I have with their font selection is that I
have to _scroll_ through their list (can't press a letter key & go to
the first item that starts with that letter)

Something you _always_ have to remember and incorporate into most
anything you program: If the program is slow then people won't use it,
and a program is as fast as it's slowest feature.  People don't like
to wait for things (Americans especially, I know -- I'm one), after
all, why are we always so estatic when an new and faster computer is
put out on the market.  (Great golly!  Look at that thing go!  My ___
couldn't do that even half that speed!!)

So do something about that amazingly slow selection (expecially if
it's required more than once every ten-fifteen minutes), even _you_
might never want to use it otherwise!

This goes for all you programmers out there!  Where would us Mac users
be if Bill A. wrote SlowDraw?

				-Kelesi
--
------------------------------------+-------------------------------
From the Macintosh of: Kevin Sitze  | Disclamer: Who the heck needs
                                    |   a disclamer?  After all, Dan
EMail: ksitze%NMSU.edu              |   Quayle doesn't.
SMail: 601 S. Melendres             +-------------------------------
       Las Cruces, NM  88005        | "We have the answers, the
------------------------------------+  trouble lies in finding the
"The difference between intelligence|  questions..."
and stupidity is that intelligence  | "The information is there,
has a limit."           - anonymous |  finding it is another story."
The dolt confuses you -- more --    |	   	    - Any consultant
------------------------------------+-------------------------------

tim@hoptoad.uucp (Tim Maroney) (05/12/89)

I agree with Robert Woodhead that you should not put that many items in
a menu.  Take a look at someone with tons of fonts using an application
with a Font menu sometime; it's horrible.  However, if you *do* want to
do this, Larry Rosenstein's suggestion should work, replacing the
defproc temporarily with one that ignores the calculate call.  However,
that requires modifying an internal Menu manager data structure
directly, and so it might break in the future (as Keith Rollins pointed
out in another connection).

I would suggest that you use your own MDEF resource, which is set up
*not* to draw the contents of the menu item.  Instead, make all the
menu items null or a blank space.  Inserting them should be easy.  Keep
the actual menu text in an external array or linked list and use that
in your drawing and calculating routines.  Turn off calculation during
your AppendMenu sequences.  This gives you speed, and does not require
dealing with internal data structures.  However, I will leave the issue
of communicating between the MDEF and the application as an (easy) exercise
for the reader.
-- 
Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim
"This signature is not to be quoted." -- Erland Sommarskog

jamesm@sco.COM (James M. Moore) (05/16/89)

In article <KSITZE.89May11090629@san_juan.nmsu.edu> ksitze@nmsu.edu (Kevin Sitze) writes:
>James,
>There's only really one major problem with using a menu for this.
>(don't spout off that a menu is the ONLY way to go, because it isn't)

Mea ne culpa!  (Or whatever the appropriate Latin is :-])  Please make
sure you've got your characters right - I didn't advocate doing this
at all.  I just responded to someone's request for a faster way to add
to a menu.  I'm no great fan of huge menus myself.
-- 

		James Moore
			jamesm@sco.com

alexis@ccnysci.UUCP (Alexis Rosen) (05/17/89)

In article <8905102252.AA29726@snoopy.UMD.EDU> res12@snoopy.UMD.EDU
(Matthew T. Russotto) writes:
>So, how do we avoid the overhead caused by CalcMenuSize? I know of one
>way:  Patch CalcMenuSize to do nothing before all the appends, and patch
>it back before the last append.  But patching traps isn't my favorite thing
>to do either.

Hm. I considered this approach for an XCMD I wrote a while ago. I decided
not to do this because it seems that this would break any ROM fixes that
might be implemented with come-from tests on that trap. Pretty unlikely, to
be sure, but there are better ways (that have already been posted).

---
Alexis Rosen
alexis@ccnysci.{uucp,bitnet}
alexis@rascal.ics.utexas.edu  (last resort)