Формы и меню
7.4. Меню
Меню и формы сочетаются как вино и сыр. Теги меню в Mozilla строятся из более простых XUL-тегов, как и большая часть остальных XUL-тегов, обсуждавшихся до этого момента. Однако меню немного сложнее по нескольким причинам:
- всплывающие меню не соответствуют нормальному потоку двумерного XML-документа;
- меню содержат много отдельных значений (элементов меню), а не одно;
- у меню сложная внутренняя структура;
- меню могут использоваться отдельно от форм, но они все равно должны соответствовать ограничениям, накладываемым другими элементами форм.
Для списков в теле документа Mozilla не использует меню. Для этого используется тег <listbox>. XUL-меню применяются только для всплывающих меню. Меню Mozilla следуют правилам дизайна, применимым к простым элементам форм, потому могут считаться своего рода простым элементом форм.
В этом разделе описывается поддержка меню в XUL, начиная от самого маленького тега. Теги, которые автор приложения может использовать для создания простых всплывающих меню, включают в себя:
<menulist> <menupopup> <menuitem> <menuseparator> <menu> <button> <toolbarbutton>
Следующие дополнительные структурирующие теги можно использовать, если нужно исследовать систему меню в XUL более внимательно. Вообще говоря, они не обязаны находиться в XUL-документе:
<dropmarker> <arrowscrollbox> <scrollbox> <autorepeatbutton>
На рисунке 7.3 показана структура полнофункционального, но простого XUL-меню с двумя элементами.
На этом рисунке показаны два аспекта одного и того же меню. В схеме слева показаны теги, указанные автором приложения. В схеме справа меню состоит из тегов, которые на самом деле создаются XUL/XBL-системой Mozilla. Очевидно, что задействуется много тегов. Система меню спроектирована так, что меню всегда составляется из полного набора данных, но ненужные части скрываются. Например, теги <autorepeatbutton> не показываются, если элементов меню так мало, что они все видны сразу. Второй пример - различные надписи и изображения. У каждого пункта меню может быть пиктограмма и клавиша доступа, а также обычный описательный текст - вместе один тег <image> и два <label>. Эти теги проявляются благодаря атрибутам, предоставленным программистом, или в зависимости от условий отображения меню.
Сложная структура тегов меню не означает сложной обработки событий. Событие command и его обработчик oncommand - все, что нам нужно для связывания простых меню с логикой работы своего приложения.
Возможны также различные виды адаптации XUL-меню на уровне тегов. Внутри меню теги <menuitem> можно заменить тегами <menuseparator> или <menu>. Снаружи теги, окружающие <menupopup>, можно переорганизовать, заменив <menulist> на что-то другое.
7.4.1. Тег <menuitem>
Тег <menuitem> представляет один пункт меню. У него есть несколько XBL-определений, из которых применяется только одно. Атрибуты этого тега со специальными значениями:
type disabled image validate src checked label accesskey acceltext crop value
Атрибут type в простых случаях не используется, но его значением может быть radio или checkbox. Эффект использования этих значений - пункт меню будет выглядеть и реагировать как эквивалентный элемент формы. Атрибут disabled делает пункт меню недоступным для выбора.
Следующий набор атрибутов относится к пиктограмме пункта меню. Если она указана, то по умолчанию появляется слева, но стандартные атрибуты выравнивания содержимого блоков вроде dir могут изменить ситуацию. И image, и src задают URL изображения пиктограммы. В стандартном меню <menulist> текущий выбранный пункт появляется на кнопке меню, если меню не раскрыто. Если используется src, то пиктограмма выбранного пункта меню также появится на кнопке меню. Если заданы и type, и src или image, пиктограмма переключателя или флажка получает больший приоритет, чем пиктограмма самого пункта меню. У validate то же значение, что и в случае тега <image> ; у checked смысл тот же, что и в тегах <radio> и <checkbox>.
Третий набор атрибутов относится к обычному сопроводительному тексту пункта меню. Этот текст может отсутствовать. Текст предоставляется label. accesskey предоставляет клавишу доступа к пункту меню, как описано в "Навигация" , "Навигация".
acceltext и crop применимы только к меню, создаваемым с помощью тега <menu>. crop поступает с текстом пункта меню так же, как и в случае <label>. acceltext предоставляет текст справа от текста пункта меню, который сообщает о том, какая комбинация клавиш выбирает этот пункт меню. Такой текст никогда не обрезается. Обычно это просто описание комбинации клавиш, например, "Shift-A". Если acceltext присутствует, отображается его значение. Если он отсутствует, но есть атрибут key, тогда текст берется из соответствующего тега <key>. Этот тег предоставит текст из своего атрибута keytext или, если таковой отсутствует, из атрибута key, или, если и его нет, то из атрибута keycode. Во всех трех случаях текст будет дополнен содержимым атрибута modifiers тега <key>. Это простое напоминание пользователю, что любое нажатие клавиш может соответствовать пункту меню, и обозначение связи между нажатиями и пунктами меню.
Атрибут value задает внутреннее значение пункта меню. Это значение может использоваться как идентификатор данного пункта меню, так как сопроводительный текст может быть переведен на другой язык системой локализации платформы.
На рисунке 7.4 показаны примеры использования многих из этих атрибутов. Изображенное окно составлено из нескольких кусков настоящего кода. Обратите внимание, что на самом деле создать два одновременно выпадающих меню нельзя.
Из рисунка 7.4 ясно, что <menuitem> очень гибок. У этого тега имеется также целый арсенал стилей, с помощью которых можно менять его внешний вид.
7.4.2. Тег <menuseparator>
Тег <menuseparator> - почти анонимный XUL-тег с некоторыми собственными правилами стилей. Он отображается как горизонтальная линия, визуально разделяющая пункты меню. Множество примеров можно найти в строке меню самой Mozilla. Этот тег находится на одном уровне с <menuitem>. У него нет особых атрибутов, но иногда полезно присваивать ему идентификатор ( id ).
Платформа Mozilla определяет этот тег при выполнении операций с меню.
7.4.3. Теги <arrowscrollbox> и <scrollbox>
Теги <arrowscrollbox> и <scrollbox> позволяют пользователю перемещаться по содержимому, расположенному в виде прямоугольника, который не помещается на экран целиком. Оба тега обсуждаются в "Навигация" , "Навигация", но у них есть применения и в меню. В меню оба создаются автоматически.
Тег <arrowscrollbox> создается для отображения слишком длинного меню, выходящего за пределы экрана. Если меню длинное, автоматически появляются кнопки <autorepeatbutton> - части <arrowscrollbox>. Проще всего увидеть работу этого тега на личной панели Навигатора Mozilla.
Для этого следует убедиться, что папка закладок находится на личной панели и что в ней много закладок. Закладок и папок должно быть столько, чтобы их список занимал, по крайней мере, половину высоты экрана. Переместите окно Навигатора так, чтобы личная панель по высоте находилась примерно в середине экрана, и нажмите на кнопку закладок (напоминаем, закладок должно быть много). Появится список закладок, вверху и внизу которого будут пиктограммы <arrowscrollbox>. Они также появятся, если задать тегу <menupopup> атрибут maxheight с каким-нибудь маленьким значением, например, 200 пикселов.
Тег <scrollbox> создает перемещаемую область внутри <arrowscrollbox>. Полосы прокрутки показываются, только если они используются внутри тега <textbox type="autocomplete">. При использовании внутри <arrowscrollbox> у него нет класса стиля и обычно его не стоит трогать.
Кнопки тега <arrowscrollbox> можно менять с помощью стилей. Они также не могут прокручивать содержимое вбок, только вверх и вниз.
7.4.4. Тег <menupopup>
Тег <menupopup> - сердце системы XUL-меню. Он отвечает за создание окна вне нормального потока размещения элементов XUL-документа и может выходить за пределы окна Mozilla. Для этого используется функциональность графической среды. У этого тега хорошая поддержка в С/C++-части Mozilla. Есть у него и XBL-определение.
Тег <menupopup> универсален. Он создает маленькое окно, действующее как <vbox>, в которое можно поместить простейшее XUL-содержимое. Почему это сделано так, не совсем ясно, но такая особенность позволяет создавать очень красиво оформленные меню. Единственное, что можно выделять в <menupopup> - теги <menuitem> и <menu>. Тег <menupopup> можно указывать и без содержимого вообще. Содержимое может добавляться позднее с помощью JavaScript, шаблонов или других XUL-техник.
При создании меню автор приложения должен использовать этот тег. Атрибуты, имеющие особое значение в <menupopup>:
popupanchor popupalign position allowevents onpopupshowing onpopupshown onpopuphiding onpopuphidden
popupanchor задает угол родительского тега, рядом с которым появится <menupopup> - так называемую опорную точку. popupalign определяет угол всплывающего меню, который будет зафиксирован относительно опорной точки. Следовательно, меню будет выравниваться по заданному углу родительского тега. Оба атрибута могут принимать одно из следующих значений:
topleft topright bottomleft bottomright none
Атрибут position предоставляет использовавшийся ранее и менее гибкий способ выравнивания, и его следует избегать. Он устарел.
Значением атрибута allowevents может быть true, но обычно этого делать не рекомендуется. В платформе Mozilla производится специальная обработка меню. На рисунке 7.3 показан сложный набор тегов, составляющих меню. Если применять к этому набору полноценную DOM-модель событий, выбор пункта меню приводил бы к созданию множества событий. Платформа Mozilla сводит эти события в одно управляемое событие команды.
Оставшиеся четыре атрибута - обработчики упоминавшихся ранее DOM- событий. Это парные цели событий. События -showing -shown запускаются в начале и в конце процесса открытия меню соответственно. События -hiding и -hidden запускаются в начале и в конце процесса сворачивания меню соответственно. Процесс отображения проходит три стадии, каждая из которых помечается Mozilla заданием значения true одному из следующих трех временных атрибутов:
menutobedisplayed menugenerated menuactive
Первый из них означает, что что-то должно произойти, но еще не произошло. Второй показывает, что содержимое меню было собрано. Третий сообщает, что меню раскрыто и получило фокус.
7.4.5. Тег <menu>
Полезное содержимое <menupopup> состоит из трех тегов: <menuitem>, <menuseparator> и <menu>. Тег <menu> очень похож на <menuitem>, но создает новое меню сбоку от уже существующего. Вот особые атрибуты этого тега:
label accesskey crop acceltext disabled
Значение этих атрибутов то же, что и в случае <menuitem>. Тег <menu> не может содержать пиктограмму, соответствующую его действию, но ее можно добавить с помощью подходящего стиля. При отображении у этого тега автоматически появляется пиктограмма в виде стрелки, говорящая о том, что здесь есть подменю. Единственный тег, который может появиться внутри <menu> - <menupopup>.
Тег <menu> также используется в строках меню:
<menulist id="foo" editable="true"/>
7.4.6. Тег <menulist>
Тег <menulist> - самый внешний тег для простых XUL-меню. Это оболочка тега <menupopup>, дающая пользователю возможность видеть что-то и взаимодействовать с чем-то, когда всплывающее меню свернуто. <menulist> отображается в виде кнопки, показывающей текущий выбранный пункт меню и кнопки раскрытия меню. В <menulist> всегда отображается текущий выбранный пункт меню.
Внутри <menulist> может находиться только тег <menupopup>. Особые атрибуты <menulist>:
src label crop accesskey disabled editable value
Смысл этих атрибутов тот же, что и у соответствующих атрибутов <menuitem>, только disabled делает недоступным все меню целиком. Новый атрибут - editable.
Название этого атрибута не совсем корректно. Если его значение - true, надпись на кнопке <menulist> заменяется текстовым полем HTML <input type="text">, куда пользователь может ввести строку. Когда фокус переходит с <menulist>, эта строка будет сравниваться с существующими пунктами меню. Если она совпадает с основным текстом какого-нибудь пункта, этот пункт станет выбранным. Все пункты меню обрабатываются так, как если бы у них был атрибут type="checkbox". Атрибут editable не дает возможности вставлять, удалять и обновлять пункты меню.
7.4.7. Варианты меню
Тег <menulist> - оболочка для тега <menupopup>. Есть и другие оболочки. Вот их полный список:
<menulist> <menulist editable="true"> <menu> <button type="menu"> <button type="menu-button> <toolbarbutton type="menu"> <toolbarbutton type="menu-button"> <textbox type="autocomplete"> <menubutton>
Использование любого из этих тегов, кроме <textbox>, подразумевает добавление <menupopup> как единственного их содержимого. <menubutton> - анонимный тег, использующийся для хранения стилей и обработчиков меню, появляющихся на панелях инструментов (см. "Навигация" , "Навигация").
В MacOS можно добавлять пункт "Настройки..." и нужные подменю в меню приложения. Чтобы это сделать, следует убедиться, что у подходящего тега <menuitem> есть специальный идентификатор id="menu_preferences".