blob: 465d24834342c7207b33387a6a5afc3901d90baf [file] [log] [blame] [edit]
/*
* BRLTTY - A background process providing access to the console screen (when in
* text mode) for a blind person using a refreshable braille display.
*
* Copyright (C) 1995-2023 by The BRLTTY Developers.
*
* BRLTTY comes with ABSOLUTELY NO WARRANTY.
*
* This is free software, placed under the terms of the
* GNU Lesser General Public License, as published by the Free Software
* Foundation; either version 2.1 of the License, or (at your option) any
* later version. Please see the file LICENSE-LGPL for details.
*
* Web Page: http://brltty.app/
*
* This software is maintained by Dave Mielke <dave@mielke.cc>.
*/
#include "prologue.h"
#include <stdio.h>
#include <string.h>
#include "log.h"
#include "log_history.h"
#include "embed.h"
#include "revision.h"
#include "api_control.h"
#include "menu.h"
#include "menu_prefs.h"
#include "prefs.h"
#include "profile.h"
#include "status_types.h"
#include "blink.h"
#include "timing.h"
#include "brl.h"
#include "spk.h"
#include "ttb.h"
#include "atb.h"
#include "ctb.h"
#include "ktb.h"
#include "tune.h"
#include "bell.h"
#include "leds.h"
#include "midi.h"
#include "core.h"
#define PREFS_MENU_ITEM_VARIABLE(name) prefsMenuItemVariable_##name
#define PREFS_MENU_ITEM_GETTER_DECLARE(name) \
static MenuItem *PREFS_MENU_ITEM_VARIABLE(name) = NULL; \
PREFS_MENU_ITEM_GETTER_PROTOTYPE(name) { \
return getPreferencesMenu()? PREFS_MENU_ITEM_VARIABLE(name): NULL; \
}
PREFS_MENU_ITEM_APPLY(PREFS_MENU_ITEM_GETTER_DECLARE)
#define NAME(name) static const MenuString itemName = {.label=name}
#define ITEM(new) MenuItem *item = (new); if (!item) goto noItem
#define TEST(property) setMenuItemTester(item, test##property)
#define CHANGED(property) setMenuItemChanged(item, changed##property)
#define SET(name) PREFS_MENU_ITEM_VARIABLE(name) = item
#define SUBMENU(variable, parent, name) \
NAME(name); \
Menu *variable = newSubmenuMenuItem(parent, &itemName); \
if (!variable) goto noItem
#define PROPERTY(variable, value) \
static unsigned char variable; \
variable = (value)
#define BLINK_PERIOD(blink) PROPERTY(period, MSECS2PREFS(getBlinkPeriod((blink))))
#define BLINK_VISIBLE(blink) PROPERTY(visible, getBlinkPercentVisible((blink)))
static int
testAdvancedSubmenu (void) {
return prefs.showAdvancedSubmenus;
}
static void
setAdvancedSubmenu (Menu *submenu) {
Menu *parent = getMenuParent(submenu);
if (parent) {
unsigned int size = getMenuSize(parent);
if (size) {
MenuItem *item = getMenuItem(parent, size-1);
if (item) setMenuItemTester(item, testAdvancedSubmenu);
}
}
}
static int
testSlidingBrailleWindow (void) {
return prefs.slidingBrailleWindow;
}
static int
changedBrailleWindowOverlap (const MenuItem *item UNUSED, unsigned char setting) {
if (setting >= textCount) return 0;
reconfigureBrailleWindow();
return 1;
}
static int
changedAutoreleaseTime (const MenuItem *item UNUSED, unsigned char setting) {
if (brl.keyTable) setKeyAutoreleaseTime(brl.keyTable, setting);
return 1;
}
static int
testAutorepeatEnabled (void) {
return prefs.autorepeatEnabled;
}
static int
changeAutorepeatProperties (BrailleDisplay *brl, int on, int delay, int interval) {
if (!canSetAutorepeatProperties(brl)) return 1;
return setAutorepeatProperties(brl, on, delay, interval);
}
static int
changedAutorepeatEnabled (const MenuItem *item UNUSED, unsigned char setting) {
return changeAutorepeatProperties(&brl, setting,
PREFS2MSECS(prefs.longPressTime),
PREFS2MSECS(prefs.autorepeatInterval));
}
static int
changedAutorepeatDelay (const MenuItem *item UNUSED, unsigned char setting) {
return changeAutorepeatProperties(&brl, prefs.autorepeatEnabled,
setting,
PREFS2MSECS(prefs.autorepeatInterval));
}
static int
changedAutorepeatInterval (const MenuItem *item UNUSED, unsigned char setting) {
return changeAutorepeatProperties(&brl, prefs.autorepeatEnabled,
PREFS2MSECS(prefs.longPressTime),
setting);
}
static int
testShowScreenCursor (void) {
return prefs.showScreenCursor;
}
static int
testBlinkingScreenCursor (void) {
return testShowScreenCursor() && prefs.blinkingScreenCursor;
}
static int
changedScreenCursorBlinkPeriod (const MenuItem *item UNUSED, unsigned char setting) {
setBlinkPeriod(&screenCursorBlinkDescriptor, PREFS2MSECS(setting));
return 1;
}
static int
changedScreenCursorBlinkPercentage (const MenuItem *item UNUSED, unsigned char setting) {
return setBlinkPercentVisible(&screenCursorBlinkDescriptor, setting);
}
static int
testShowAttributes (void) {
return prefs.showAttributes;
}
static int
testBlinkingAttributes (void) {
return testShowAttributes() && prefs.blinkingAttributes;
}
static int
changedAttributesUnderlineBlinkPeriod (const MenuItem *item UNUSED, unsigned char setting) {
setBlinkPeriod(&attributesUnderlineBlinkDescriptor, PREFS2MSECS(setting));
return 1;
}
static int
changedAttributesUnderlineBlinkPercentage (const MenuItem *item UNUSED, unsigned char setting) {
return setBlinkPercentVisible(&attributesUnderlineBlinkDescriptor, setting);
}
static int
testBlinkingCapitals (void) {
return prefs.blinkingCapitals;
}
static int
changedUppercaseLettersBlinkPeriod (const MenuItem *item UNUSED, unsigned char setting) {
setBlinkPeriod(&uppercaseLettersBlinkDescriptor, PREFS2MSECS(setting));
return 1;
}
static int
changedUppercaseLettersBlinkPercentage (const MenuItem *item UNUSED, unsigned char setting) {
return setBlinkPercentVisible(&uppercaseLettersBlinkDescriptor, setting);
}
static int
testBrailleFirmness (void) {
return canSetBrailleFirmness(&brl);
}
static int
changedBrailleFirmness (const MenuItem *item UNUSED, unsigned char setting) {
return setBrailleFirmness(&brl, setting);
}
static int
testTouchSensitivity (void) {
return canSetTouchSensitivity(&brl);
}
static int
changedTouchSensitivity (const MenuItem *item UNUSED, unsigned char setting) {
return setTouchSensitivity(&brl, setting);
}
static int
testConsoleBellAlert (void) {
return canMonitorConsoleBell();
}
static int
changedConsoleBellAlert (const MenuItem *item UNUSED, unsigned char setting) {
return setConsoleBellMonitoring(setting);
}
static int
testKeyboardLedAlerts (void) {
return canMonitorLeds();
}
static int
changedKeyboardLedAlerts (const MenuItem *item UNUSED, unsigned char setting) {
return setLedMonitoring(setting);
}
static int
testAlertTunes (void) {
return prefs.alertTunes;
}
static int
changedAlertTunes (const MenuItem *item UNUSED, unsigned char setting) {
api.updateParameter(BRLAPI_PARAM_AUDIBLE_ALERTS, 0);
return 1;
}
static int
changedTuneDevice (const MenuItem *item UNUSED, unsigned char setting) {
return tuneSetDevice(setting);
}
#ifdef HAVE_PCM_SUPPORT
static int
testTunesPcm (void) {
return testAlertTunes() && (prefs.tuneDevice == tdPcm);
}
#endif /* HAVE_PCM_SUPPORT */
#ifdef HAVE_MIDI_SUPPORT
static int
testTunesMidi (void) {
return testAlertTunes() && (prefs.tuneDevice == tdMidi);
}
#endif /* HAVE_MIDI_SUPPORT */
#ifdef HAVE_FM_SUPPORT
static int
testTunesFm (void) {
return testAlertTunes() && (prefs.tuneDevice == tdFm);
}
#endif /* HAVE_FM_SUPPORT */
#ifdef ENABLE_SPEECH_SUPPORT
static int
testSpeechVolume (void) {
return canSetSpeechVolume(&spk);
}
static int
changedSpeechVolume (const MenuItem *item UNUSED, unsigned char setting) {
return setSpeechVolume(&spk, setting, !prefs.autospeak);
}
static void
formatSpeechVolume (Menu *menu, unsigned char volume, char *buffer, size_t size) {
snprintf(
buffer, size, "%d", toNormalizedSpeechVolume(volume)
);
}
static int
testSpeechRate (void) {
return canSetSpeechRate(&spk);
}
static int
changedSpeechRate (const MenuItem *item UNUSED, unsigned char setting) {
return setSpeechRate(&spk, setting, !prefs.autospeak);
}
static void
formatSpeechRate (Menu *menu, unsigned char rate, char *buffer, size_t size) {
snprintf(
buffer, size, "%d", toNormalizedSpeechRate(rate)
);
}
static int
testSpeechPitch (void) {
return canSetSpeechPitch(&spk);
}
static int
changedSpeechPitch (const MenuItem *item UNUSED, unsigned char setting) {
return setSpeechPitch(&spk, setting, !prefs.autospeak);
}
static void
formatSpeechPitch (Menu *menu, unsigned char pitch, char *buffer, size_t size) {
snprintf(
buffer, size, "%d", toNormalizedSpeechPitch(pitch)
);
}
static int
testSpeechPunctuation (void) {
return canSetSpeechPunctuation(&spk);
}
static int
changedSpeechPunctuation (const MenuItem *item UNUSED, unsigned char setting) {
return setSpeechPunctuation(&spk, setting, !prefs.autospeak);
}
static int
testAutospeak (void) {
return prefs.autospeak;
}
static int
testShowSpeechCursor (void) {
return prefs.showSpeechCursor;
}
static int
testBlinkingSpeechCursor (void) {
return testShowSpeechCursor() && prefs.blinkingSpeechCursor;
}
static int
changedSpeechCursorBlinkPeriod (const MenuItem *item UNUSED, unsigned char setting) {
setBlinkPeriod(&speechCursorBlinkDescriptor, PREFS2MSECS(setting));
return 1;
}
static int
changedSpeechCursorBlinkPercentage (const MenuItem *item UNUSED, unsigned char setting) {
return setBlinkPercentVisible(&speechCursorBlinkDescriptor, setting);
}
#endif /* ENABLE_SPEECH_SUPPORT */
static int
testShowDate (void) {
return prefs.datePosition != dpNone;
}
static int
testStatusPosition (void) {
return !haveStatusCells();
}
static int
changedStatusPosition (const MenuItem *item UNUSED, unsigned char setting UNUSED) {
reconfigureBrailleWindow();
return 1;
}
static int
testStatusCount (void) {
return testStatusPosition() && (prefs.statusPosition != spNone);
}
static int
changedStatusCount (const MenuItem *item UNUSED, unsigned char setting UNUSED) {
reconfigureBrailleWindow();
return 1;
}
static int
testStatusSeparator (void) {
return testStatusCount();
}
static int
changedStatusSeparator (const MenuItem *item UNUSED, unsigned char setting UNUSED) {
reconfigureBrailleWindow();
return 1;
}
static int
testStatusField (unsigned char index) {
return (haveStatusCells() || (prefs.statusPosition != spNone)) &&
((index == 0) || (prefs.statusFields[index-1] != sfEnd));
}
static int
changedStatusField (unsigned char index, unsigned char setting) {
switch (setting) {
case sfGeneric:
if (index > 0) return 0;
if (!haveStatusCells()) return 0;
if (!braille->statusFields) return 0;
if (*braille->statusFields != sfGeneric) return 0;
/* fall through */
case sfEnd:
if (prefs.statusFields[index+1] != sfEnd) return 0;
break;
default:
if ((index > 0) && (prefs.statusFields[index-1] == sfGeneric)) return 0;
break;
}
reconfigureBrailleWindow();
return 1;
}
#define STATUS_FIELD_HANDLERS(n) \
static int testStatusField##n (void) { return testStatusField(n-1); } \
static int changedStatusField##n (const MenuItem *item UNUSED, unsigned char setting) { return changedStatusField(n-1, setting); }
STATUS_FIELD_HANDLERS(1)
STATUS_FIELD_HANDLERS(2)
STATUS_FIELD_HANDLERS(3)
STATUS_FIELD_HANDLERS(4)
STATUS_FIELD_HANDLERS(5)
STATUS_FIELD_HANDLERS(6)
STATUS_FIELD_HANDLERS(7)
STATUS_FIELD_HANDLERS(8)
STATUS_FIELD_HANDLERS(9)
#undef STATUS_FIELD_HANDLERS
static int
changedSkipIdenticalLines (const MenuItem *item, unsigned char setting UNUSED) {
api.updateParameter(BRLAPI_PARAM_SKIP_IDENTICAL_LINES, 0);
return 1;
}
static int
changedTextTable (const MenuItem *item, unsigned char setting UNUSED) {
return changeTextTable(getMenuItemValue(item));
}
static int
changedAttributesTable (const MenuItem *item, unsigned char setting UNUSED) {
return changeAttributesTable(getMenuItemValue(item));
}
static int
changedKeyboardTable (const MenuItem *item, unsigned char setting UNUSED) {
return changeKeyboardTable(getMenuItemValue(item));
}
static int
testComputerBraille (void) {
return !isContractedBraille();
}
static int
testContractedBraille (void) {
return isContractedBraille();
}
static int
changedContractedBraille (const MenuItem *item, unsigned char setting UNUSED) {
setContractedBraille(setting);
api.updateParameter(BRLAPI_PARAM_LITERARY_BRAILLE, 0);
return 1;
}
static int
changedContractionTable (const MenuItem *item, unsigned char setting UNUSED) {
return changeContractionTable(getMenuItemValue(item));
}
static int
changedComputerBraille (const MenuItem *item, unsigned char setting UNUSED) {
setSixDotComputerBraille(setting);
api.updateParameter(BRLAPI_PARAM_COMPUTER_BRAILLE_CELL_SIZE, 0);
return 1;
}
static int
testInputTable (void) {
return !!brl.keyTable;
}
static int
testKeyboardTable (void) {
return !!keyboardTable;
}
static MenuItem *
newProfileMenuItem (Menu *menu, const ProfileDescriptor *profile) {
MenuString name = {.label = profile->category};
return newFilesMenuItem(menu, &name, opt_tablesDirectory, PROFILES_SUBDIRECTORY, profile->extension, "", 1);
}
static int
changedProfile (const ProfileDescriptor *profile, const MenuItem *item) {
const char *value = getMenuItemValue(item);
if (*value) {
activateProfile(profile, opt_tablesDirectory, value);
} else {
deactivateProfile(profile);
}
return 1;
}
static int
changedLanguageProfile (const MenuItem *item, unsigned char setting UNUSED) {
return changedProfile(&languageProfile, item);
}
static MenuItem *
newStatusFieldMenuItem (
Menu *menu, unsigned char number,
MenuItemTester *test, MenuItemChanged *changed
) {
static const MenuString strings[] = {
[sfEnd] = {.label=strtext("End")},
[sfWindowCoordinates2] = {.label=strtext("Window Coordinates"), .comment=strtext("2 cells")},
[sfWindowColumn] = {.label=strtext("Window Column"), .comment=strtext("1 cell")},
[sfWindowRow] = {.label=strtext("Window Row"), .comment=strtext("1 cell")},
[sfCursorCoordinates2] = {.label=strtext("Cursor Coordinates"), .comment=strtext("2 cells")},
[sfCursorColumn] = {.label=strtext("Cursor Column"), .comment=strtext("1 cell")},
[sfCursorRow] = {.label=strtext("Cursor Row"), .comment=strtext("1 cell")},
[sfCursorAndWindowColumn2] = {.label=strtext("Cursor and Window Column"), .comment=strtext("2 cells")},
[sfCursorAndWindowRow2] = {.label=strtext("Cursor and Window Row"), .comment=strtext("2 cells")},
[sfScreenNumber] = {.label=strtext("Screen Number"), .comment=strtext("1 cell")},
[sfStateDots] = {.label=strtext("State Dots"), .comment=strtext("1 cell")},
[sfStateLetter] = {.label=strtext("State Letter"), .comment=strtext("1 cell")},
[sfTime] = {.label=strtext("Time"), .comment=strtext("2 cells")},
[sfAlphabeticWindowCoordinates] = {.label=strtext("Alphabetic Window Coordinates"), .comment=strtext("1 cell")},
[sfAlphabeticCursorCoordinates] = {.label=strtext("Alphabetic Cursor Coordinates"), .comment=strtext("1 cell")},
[sfGeneric] = {.label=strtext("Generic")},
[sfCursorCoordinates3] = {.label=strtext("Cursor Coordinates"), .comment=strtext("3 cells")},
[sfWindowCoordinates3] = {.label=strtext("Window Coordinates"), .comment=strtext("3 cells")},
[sfCursorAndWindowColumn3] = {.label=strtext("Cursor and Window Column"), .comment=strtext("3 cells")},
[sfCursorAndWindowRow3] = {.label=strtext("Cursor and Window Row"), .comment=strtext("3 cells")},
[sfSpace] = {.label=strtext("Space"), .comment=strtext("1 cell")},
};
MenuString name = {
.label = strtext("Status Field")
};
char *comment;
{
char buffer[0X3];
snprintf(buffer, sizeof(buffer), "%u", number);
name.comment = comment = strdup(buffer);
}
if (comment) {
MenuItem *item = newEnumeratedMenuItem(menu, &prefs.statusFields[number-1], &name, strings);
if (item) {
setMenuItemTester(item, test);
setMenuItemChanged(item, changed);
return item;
}
free(comment);
} else {
logMallocError();
}
return NULL;
}
static MenuItem *
newBlinkVisibleMenuItem (Menu *menu, unsigned char *setting, const MenuString *name) {
return newPercentMenuItem(menu, setting, name, 5);
}
#if defined(HAVE_PCM_SUPPORT) || defined(HAVE_MIDI_SUPPORT) || defined(HAVE_FM_SUPPORT)
static MenuItem *
newVolumeMenuItem (Menu *menu, unsigned char *setting, const MenuString *name) {
return newPercentMenuItem(menu, setting, name, 5);
}
#endif /* defined(HAVE_PCM_SUPPORT) || defined(HAVE_MIDI_SUPPORT) || defined(HAVE_FM_SUPPORT) */
#ifdef HAVE_MIDI_SUPPORT
static MenuString *
makeMidiInstrumentMenuStrings (void) {
MenuString *strings = malloc(midiInstrumentCount * sizeof(*strings));
if (strings) {
for (unsigned int instrument=0; instrument<midiInstrumentCount; instrument+=1) {
MenuString *string = &strings[instrument];
string->label = midiInstrumentTable[instrument];
string->comment = midiGetInstrumentGroup(instrument);
}
}
return strings;
}
#endif /* HAVE_MIDI_SUPPORT */
static Menu *logMessagesMenu = NULL;
static const LogEntry *newestLogMessage = NULL;
static int
addNewLogMessages (const LogEntry *message) {
if (message == newestLogMessage) return 1;
if (!addNewLogMessages(getPreviousLogEntry(message))) return 0;
MenuString name;
const TimeValue *time = getLogEntryTime(message);
unsigned int count = getLogEntryCount(message);
if (time) {
char buffer[0X20];
formatSeconds(buffer, sizeof(buffer), "%Y-%m-%d@%H:%M:%S", time->seconds);
name.label = strdup(buffer);
} else {
name.label = NULL;
}
if (count > 1) {
char buffer[0X10];
snprintf(buffer, sizeof(buffer), "(%u)", count);
name.comment = strdup(buffer);
} else {
name.comment = NULL;
}
MenuItem *item = newTextMenuItem(logMessagesMenu, &name, getLogEntryText(message));
if (!item) return 0;
newestLogMessage = message;
return 1;
}
int
updateLogMessagesSubmenu (void) {
return addNewLogMessages(getNewestLogMessage(1));
}
static Menu *
makePreferencesMenu (void) {
static const MenuString cursorStyles[] = {
[csBottomDots] = {.label=strtext("Underline"), .comment=strtext("dots 7 and 8")},
[csAllDots] = {.label=strtext("Block"), .comment=strtext("all dots")},
[csLowerLeftDot] = {.label=strtext("Lower Left Dot"), .comment=strtext("dot 7")},
[csLowerRightDot] = {.label=strtext("Lower Right Dot"), .comment=strtext("dot 8")},
[csNoDots] = {.label=strtext("Hide"), .comment=strtext("no dots")},
};
Menu *rootMenu = newMenu();
if (!rootMenu) goto noMenu;
{
NAME(strtext("Save on Exit"));
ITEM(newBooleanMenuItem(rootMenu, &prefs.saveOnExit, &itemName));
}
{
SUBMENU(optionsSubmenu, rootMenu, strtext("Menu Options"));
{
NAME(strtext("Show Submenu Sizes"));
ITEM(newBooleanMenuItem(optionsSubmenu, &prefs.showSubmenuSizes, &itemName));
}
{
NAME(strtext("Show Advanced Submenus"));
ITEM(newBooleanMenuItem(optionsSubmenu, &prefs.showAdvancedSubmenus, &itemName));
}
{
NAME(strtext("Show All Items"));
ITEM(newBooleanMenuItem(optionsSubmenu, &prefs.showAllItems, &itemName));
}
}
{
SUBMENU(presentationSubmenu, rootMenu, strtext("Braille Presentation"));
{
static const MenuString strings[] = {
{.label=strtext("Computer Braille")},
{.label=strtext("Contracted Braille")},
};
NAME(strtext("Braille Variant"));
PROPERTY(yes, isContractedBraille());
ITEM(newEnumeratedMenuItem(presentationSubmenu, &yes, &itemName, strings));
CHANGED(ContractedBraille);
}
{
NAME(strtext("Expand Current Word"));
ITEM(newBooleanMenuItem(presentationSubmenu, &prefs.expandCurrentWord, &itemName));
TEST(ContractedBraille);
}
{
static const MenuString strings[] = {
[CTB_CAP_NONE] = {.label=strtext("No Capitalization")},
[CTB_CAP_SIGN] = {.label=strtext("Use Capital Sign")},
[CTB_CAP_DOT7] = {.label=strtext("Superimpose Dot 7")},
};
NAME(strtext("Capitalization Mode"));
ITEM(newEnumeratedMenuItem(presentationSubmenu, &prefs.capitalizationMode, &itemName, strings));
TEST(ContractedBraille);
}
{
static const MenuString strings[] = {
{.label=strtext("8-dot")},
{.label=strtext("6-dot")},
};
NAME(strtext("Computer Braille Cell Type"));
PROPERTY(yes, isSixDotComputerBraille());
ITEM(newEnumeratedMenuItem(presentationSubmenu, &yes, &itemName, strings));
TEST(ComputerBraille);
CHANGED(ComputerBraille);
}
{
static const MenuString strings[] = {
[BRL_FIRMNESS_MINIMUM] = {.label=strtext("Minimum")},
[BRL_FIRMNESS_LOW] = {.label=strtext("Low")},
[BRL_FIRMNESS_MEDIUM] = {.label=strtext("Medium")},
[BRL_FIRMNESS_HIGH] = {.label=strtext("High")},
[BRL_FIRMNESS_MAXIMUM] = {.label=strtext("Maximum")},
};
NAME(strtext("Braille Firmness"));
ITEM(newEnumeratedMenuItem(presentationSubmenu, &prefs.brailleFirmness, &itemName, strings));
TEST(BrailleFirmness);
CHANGED(BrailleFirmness);
}
}
{
SUBMENU(indicatorsSubmenu, rootMenu, strtext("Text Indicators"));
{
NAME(strtext("Show Screen Cursor"));
ITEM(newBooleanMenuItem(indicatorsSubmenu, &prefs.showScreenCursor, &itemName));
}
{
NAME(strtext("Screen Cursor Style"));
ITEM(newEnumeratedMenuItem(indicatorsSubmenu, &prefs.screenCursorStyle, &itemName, cursorStyles));
TEST(ShowScreenCursor);
}
{
NAME(strtext("Blinking Screen Cursor"));
ITEM(newBooleanMenuItem(indicatorsSubmenu, &prefs.blinkingScreenCursor, &itemName));
TEST(ShowScreenCursor);
}
{
NAME(strtext("Screen Cursor Blink Period"));
BLINK_PERIOD(&screenCursorBlinkDescriptor);
ITEM(newTimeMenuItem(indicatorsSubmenu, &period, &itemName));
TEST(BlinkingScreenCursor);
CHANGED(ScreenCursorBlinkPeriod);
}
{
NAME(strtext("Screen Cursor Percent Visible"));
BLINK_VISIBLE(&screenCursorBlinkDescriptor);
ITEM(newBlinkVisibleMenuItem(indicatorsSubmenu, &visible, &itemName));
TEST(BlinkingScreenCursor);
CHANGED(ScreenCursorBlinkPercentage);
}
{
NAME(strtext("Show Attributes"));
ITEM(newBooleanMenuItem(indicatorsSubmenu, &prefs.showAttributes, &itemName));
}
{
NAME(strtext("Blinking Attributes"));
ITEM(newBooleanMenuItem(indicatorsSubmenu, &prefs.blinkingAttributes, &itemName));
TEST(ShowAttributes);
}
{
NAME(strtext("Attributes Blink Period"));
BLINK_PERIOD(&attributesUnderlineBlinkDescriptor);
ITEM(newTimeMenuItem(indicatorsSubmenu, &period, &itemName));
TEST(BlinkingAttributes);
CHANGED(AttributesUnderlineBlinkPeriod);
}
{
NAME(strtext("Attributes Percent Visible"));
BLINK_VISIBLE(&attributesUnderlineBlinkDescriptor);
ITEM(newBlinkVisibleMenuItem(indicatorsSubmenu, &visible, &itemName));
TEST(BlinkingAttributes);
CHANGED(AttributesUnderlineBlinkPercentage);
}
{
NAME(strtext("Blinking Capitals"));
ITEM(newBooleanMenuItem(indicatorsSubmenu, &prefs.blinkingCapitals, &itemName));
}
{
NAME(strtext("Capitals Blink Period"));
BLINK_PERIOD(&uppercaseLettersBlinkDescriptor);
ITEM(newTimeMenuItem(indicatorsSubmenu, &period, &itemName));
TEST(BlinkingCapitals);
CHANGED(UppercaseLettersBlinkPeriod);
}
{
NAME(strtext("Capitals Percent Visible"));
BLINK_VISIBLE(&uppercaseLettersBlinkDescriptor);
ITEM(newBlinkVisibleMenuItem(indicatorsSubmenu, &visible, &itemName));
TEST(BlinkingCapitals);
CHANGED(UppercaseLettersBlinkPercentage);
}
}
{
SUBMENU(navigationSubmenu, rootMenu, strtext("Navigation Options"));
{
NAME(strtext("Word Wrap"));
ITEM(newBooleanMenuItem(navigationSubmenu, &prefs.wordWrap, &itemName));
}
{
NAME(strtext("Skip Identical Lines"));
ITEM(newBooleanMenuItem(navigationSubmenu, &prefs.skipIdenticalLines, &itemName));
CHANGED(SkipIdenticalLines);
}
{
NAME(strtext("Skip Blank Braille Windows"));
ITEM(newBooleanMenuItem(navigationSubmenu, &prefs.skipBlankBrailleWindows, &itemName));
}
{
static const MenuString strings[] = {
[sbwAll] = {.label=strtext("All")},
[sbwEndOfLine] = {.label=strtext("End of Line")},
[sbwRestOfLine] = {.label=strtext("Rest of Line")},
};
NAME(strtext("Skip Which Blank Braille Windows"));
ITEM(newEnumeratedMenuItem(navigationSubmenu, &prefs.skipBlankBrailleWindowsMode, &itemName, strings));
}
{
NAME(strtext("Sliding Braille Window"));
ITEM(newBooleanMenuItem(navigationSubmenu, &prefs.slidingBrailleWindow, &itemName));
}
{
NAME(strtext("Eager Sliding Braille Window"));
ITEM(newBooleanMenuItem(navigationSubmenu, &prefs.eagerSlidingBrailleWindow, &itemName));
TEST(SlidingBrailleWindow);
}
{
NAME(strtext("Braille Window Overlap"));
ITEM(newNumericMenuItem(navigationSubmenu, &prefs.brailleWindowOverlap, &itemName, 0, 20, 1, strtext("cells"), NULL));
CHANGED(BrailleWindowOverlap);
}
{
NAME(strtext("Scroll-aware Cursor Navigation"));
ITEM(newBooleanMenuItem(navigationSubmenu, &prefs.scrollAwareCursorNavigation, &itemName));
}
{
static const MenuString strings[] = {
[ctdNone] = {.label=strtext("None")},
[ctd250ms] = {.label=strtext("250 milliseconds")},
[ctd500ms] = {.label=strtext("500 milliseconds")},
[ctd1s] = {.label=strtext("1 second")},
[ctd2s] = {.label=strtext("2 seconds")},
};
NAME(strtext("Cursor Tracking Delay"));
ITEM(newEnumeratedMenuItem(navigationSubmenu, &prefs.cursorTrackingDelay, &itemName, strings));
}
{
NAME(strtext("Track Screen Scroll"));
ITEM(newBooleanMenuItem(navigationSubmenu, &prefs.trackScreenScroll, &itemName));
}
#ifdef HAVE_LIBGPM
{
NAME(strtext("Track Screen Pointer"));
ITEM(newBooleanMenuItem(navigationSubmenu, &prefs.trackScreenPointer, &itemName));
}
#endif /* HAVE_LIBGPM */
{
NAME(strtext("Highlight Braille Window Location"));
ITEM(newBooleanMenuItem(navigationSubmenu, &prefs.highlightBrailleWindowLocation, &itemName));
}
{
NAME(strtext("Start Selection with Routing Key"));
ITEM(newBooleanMenuItem(navigationSubmenu, &prefs.startSelectionWithRoutingKey, &itemName));
}
}
{
SUBMENU(typingSubmenu, rootMenu, strtext("Braille Typing"));
{
NAME(strtext("Keyboard Enabled"));
ITEM(newBooleanMenuItem(typingSubmenu, &prefs.brailleKeyboardEnabled, &itemName));
}
{
static const MenuString strings[] = {
[BRL_TYPING_TEXT] = {.label=strtext("Translated via Text Table")},
[BRL_TYPING_DOTS] = {.label=strtext("Dots via Unicode Braille")},
};
NAME(strtext("Typing Mode"));
ITEM(newEnumeratedMenuItem(typingSubmenu, &prefs.brailleTypingMode, &itemName, strings));
}
{
NAME(strtext("Quick Space"));
ITEM(newBooleanMenuItem(typingSubmenu, &prefs.brailleQuickSpace, &itemName));
}
}
{
SUBMENU(inputSubmenu, rootMenu, strtext("Input Options"));
{
static const MenuString strings[] = {
[atOff] = {.label=strtext("Off")},
[at5s] = {.label=strtext("5 seconds")},
[at10s] = {.label=strtext("10 seconds")},
[at20s] = {.label=strtext("20 seconds")},
[at40s] = {.label=strtext("40 seconds")},
};
NAME(strtext("Autorelease Time"));
ITEM(newEnumeratedMenuItem(inputSubmenu, &prefs.autoreleaseTime, &itemName, strings));
CHANGED(AutoreleaseTime);
}
{
NAME(strtext("On First Release"));
ITEM(newBooleanMenuItem(inputSubmenu, &prefs.onFirstRelease, &itemName));
}
{
NAME(strtext("Long Press Time"));
ITEM(newTimeMenuItem(inputSubmenu, &prefs.longPressTime, &itemName));
CHANGED(AutorepeatDelay);
}
{
NAME(strtext("Autorepeat Enabled"));
ITEM(newBooleanMenuItem(inputSubmenu, &prefs.autorepeatEnabled, &itemName));
CHANGED(AutorepeatEnabled);
}
{
NAME(strtext("Autorepeat Interval"));
ITEM(newTimeMenuItem(inputSubmenu, &prefs.autorepeatInterval, &itemName));
TEST(AutorepeatEnabled);
CHANGED(AutorepeatInterval);
}
{
NAME(strtext("Autorepeat Panning"));
ITEM(newBooleanMenuItem(inputSubmenu, &prefs.autorepeatPanning, &itemName));
TEST(AutorepeatEnabled);
}
{
NAME(strtext("Touch Navigation"));
ITEM(newBooleanMenuItem(inputSubmenu, &prefs.touchNavigation, &itemName));
TEST(TouchSensitivity);
}
{
static const MenuString strings[] = {
[BRL_SENSITIVITY_MINIMUM] = {.label=strtext("Minimum")},
[BRL_SENSITIVITY_LOW] = {.label=strtext("Low")},
[BRL_SENSITIVITY_MEDIUM] = {.label=strtext("Medium")},
[BRL_SENSITIVITY_HIGH] = {.label=strtext("High")},
[BRL_SENSITIVITY_MAXIMUM] = {.label=strtext("Maximum")},
};
NAME(strtext("Touch Sensitivity"));
ITEM(newEnumeratedMenuItem(inputSubmenu, &prefs.touchSensitivity, &itemName, strings));
TEST(TouchSensitivity);
CHANGED(TouchSensitivity);
}
{
NAME(strtext("Keyboard Table"));
ITEM(newFilesMenuItem(inputSubmenu, &itemName, opt_tablesDirectory, KEYBOARD_TABLES_SUBDIRECTORY, KEY_TABLE_EXTENSION, opt_keyboardTable, 1));
CHANGED(KeyboardTable);
SET(keyboardTable);
}
}
{
SUBMENU(alertsSubmenu, rootMenu, strtext("Event Alerts"));
{
NAME(strtext("Console Bell Alert"));
ITEM(newBooleanMenuItem(alertsSubmenu, &prefs.consoleBellAlert, &itemName));
TEST(ConsoleBellAlert);
CHANGED(ConsoleBellAlert);
}
{
NAME(strtext("Keyboard LED Alerts"));
ITEM(newBooleanMenuItem(alertsSubmenu, &prefs.keyboardLedAlerts, &itemName));
TEST(KeyboardLedAlerts);
CHANGED(KeyboardLedAlerts);
}
{
NAME(strtext("Alert Tunes"));
ITEM(newBooleanMenuItem(alertsSubmenu, &prefs.alertTunes, &itemName));
CHANGED(AlertTunes);
}
{
static const MenuString strings[] = {
[tdBeeper] = {.label=strtext("Beeper"), .comment=strtext("console tone generator")},
[tdPcm] = {.label=strtext("PCM"), .comment=strtext("soundcard digital audio")},
[tdMidi] = {.label=strtext("MIDI"), .comment=strtext("Musical Instrument Digital Interface")},
[tdFm] = {.label=strtext("FM"), .comment=strtext("soundcard synthesizer")},
};
NAME(strtext("Tune Device"));
ITEM(newEnumeratedMenuItem(alertsSubmenu, &prefs.tuneDevice, &itemName, strings));
TEST(AlertTunes);
CHANGED(TuneDevice);
}
#ifdef HAVE_PCM_SUPPORT
{
NAME(strtext("PCM Volume"));
ITEM(newVolumeMenuItem(alertsSubmenu, &prefs.pcmVolume, &itemName));
TEST(TunesPcm);
}
#endif /* HAVE_PCM_SUPPORT */
#ifdef HAVE_MIDI_SUPPORT
{
NAME(strtext("MIDI Volume"));
ITEM(newVolumeMenuItem(alertsSubmenu, &prefs.midiVolume, &itemName));
TEST(TunesMidi);
}
{
const MenuString *strings = makeMidiInstrumentMenuStrings();
if (!strings) goto noItem;
{
NAME(strtext("MIDI Instrument"));
ITEM(newStringsMenuItem(alertsSubmenu, &prefs.midiInstrument, &itemName, strings, midiInstrumentCount));
TEST(TunesMidi);
}
}
#endif /* HAVE_MIDI_SUPPORT */
#ifdef HAVE_FM_SUPPORT
{
NAME(strtext("FM Volume"));
ITEM(newVolumeMenuItem(alertsSubmenu, &prefs.fmVolume, &itemName));
TEST(TunesFm);
}
#endif /* HAVE_FM_SUPPORT */
{
NAME(strtext("Alert Dots"));
ITEM(newBooleanMenuItem(alertsSubmenu, &prefs.alertDots, &itemName));
}
{
NAME(strtext("Alert Messages"));
ITEM(newBooleanMenuItem(alertsSubmenu, &prefs.alertMessages, &itemName));
}
#ifdef ENABLE_SPEECH_SUPPORT
{
NAME(strtext("Speak Key Context"));
ITEM(newBooleanMenuItem(alertsSubmenu, &prefs.speakKeyContext, &itemName));
}
{
NAME(strtext("Speak Modifier Key"));
ITEM(newBooleanMenuItem(alertsSubmenu, &prefs.speakModifierKey, &itemName));
}
#endif /* ENABLE_SPEECH_SUPPORT */
}
#ifdef ENABLE_SPEECH_SUPPORT
{
SUBMENU(autospeakSubmenu, rootMenu, strtext("Autospeak Options"));
{
NAME(strtext("Autospeak"));
ITEM(newBooleanMenuItem(autospeakSubmenu, &prefs.autospeak, &itemName));
}
{
NAME(strtext("Speak Selected Line"));
ITEM(newBooleanMenuItem(autospeakSubmenu, &prefs.autospeakSelectedLine, &itemName));
TEST(Autospeak);
}
{
NAME(strtext("Speak Selected Character"));
ITEM(newBooleanMenuItem(autospeakSubmenu, &prefs.autospeakSelectedCharacter, &itemName));
TEST(Autospeak);
}
{
NAME(strtext("Speak Inserted Characters"));
ITEM(newBooleanMenuItem(autospeakSubmenu, &prefs.autospeakInsertedCharacters, &itemName));
TEST(Autospeak);
}
{
NAME(strtext("Speak Deleted Characters"));
ITEM(newBooleanMenuItem(autospeakSubmenu, &prefs.autospeakDeletedCharacters, &itemName));
TEST(Autospeak);
}
{
NAME(strtext("Speak Replaced Characters"));
ITEM(newBooleanMenuItem(autospeakSubmenu, &prefs.autospeakReplacedCharacters, &itemName));
TEST(Autospeak);
}
{
NAME(strtext("Speak Completed Words"));
ITEM(newBooleanMenuItem(autospeakSubmenu, &prefs.autospeakCompletedWords, &itemName));
TEST(Autospeak);
}
{
NAME(strtext("Speak Line Indent"));
ITEM(newBooleanMenuItem(autospeakSubmenu, &prefs.autospeakLineIndent, &itemName));
TEST(Autospeak);
}
}
{
SUBMENU(speechSubmenu, rootMenu, strtext("Speech Options"));
{
NAME(strtext("Speech Volume"));
ITEM(newNumericMenuItem(speechSubmenu, &prefs.speechVolume, &itemName, 0, SPK_VOLUME_MAXIMUM, 1, "%", formatSpeechVolume));
TEST(SpeechVolume);
CHANGED(SpeechVolume);
}
{
NAME(strtext("Speech Rate"));
ITEM(newNumericMenuItem(speechSubmenu, &prefs.speechRate, &itemName, 0, SPK_RATE_MAXIMUM, 1, NULL, formatSpeechRate));
TEST(SpeechRate);
CHANGED(SpeechRate);
}
{
NAME(strtext("Speech Pitch"));
ITEM(newNumericMenuItem(speechSubmenu, &prefs.speechPitch, &itemName, 0, SPK_PITCH_MAXIMUM, 1, NULL, formatSpeechPitch));
TEST(SpeechPitch);
CHANGED(SpeechPitch);
}
{
static const MenuString strings[] = {
[SPK_PUNCTUATION_NONE] = {.label=strtext("None")},
[SPK_PUNCTUATION_SOME] = {.label=strtext("Some")},
[SPK_PUNCTUATION_ALL] = {.label=strtext("All")},
};
NAME(strtext("Speech Punctuation"));
ITEM(newEnumeratedMenuItem(speechSubmenu, &prefs.speechPunctuation, &itemName, strings));
TEST(SpeechPunctuation);
CHANGED(SpeechPunctuation);
}
{
static const MenuString strings[] = {
[sucNone] = {.label=strtext("None")},
// "cap" here, used during speech output, is short for "capital".
// It is spoken just before an uppercase letter, e.g. "cap A".
[sucSayCap] = {.label=strtext("Say Cap")},
[sucRaisePitch] = {.label=strtext("Raise Pitch")},
};
NAME(strtext("Speech Uppercase Indicator"));
ITEM(newEnumeratedMenuItem(speechSubmenu, &prefs.speechUppercaseIndicator, &itemName, strings));
}
{
static const MenuString strings[] = {
[swsNone] = {.label=strtext("None")},
[swsSaySpace] = {.label=strtext("Say Space")},
};
NAME(strtext("Speech Whitespace Indicator"));
ITEM(newEnumeratedMenuItem(speechSubmenu, &prefs.speechWhitespaceIndicator, &itemName, strings));
}
{
static const MenuString strings[] = {
[sayImmediate] = {.label=strtext("Immediate")},
[sayEnqueue] = {.label=strtext("Enqueue")},
};
NAME(strtext("Say Line Mode"));
ITEM(newEnumeratedMenuItem(speechSubmenu, &prefs.sayLineMode, &itemName, strings));
}
{
NAME(strtext("Show Speech Cursor"));
ITEM(newBooleanMenuItem(speechSubmenu, &prefs.showSpeechCursor, &itemName));
}
{
NAME(strtext("Speech Cursor Style"));
ITEM(newEnumeratedMenuItem(speechSubmenu, &prefs.speechCursorStyle, &itemName, cursorStyles));
TEST(ShowSpeechCursor);
}
{
NAME(strtext("Blinking Speech Cursor"));
ITEM(newBooleanMenuItem(speechSubmenu, &prefs.blinkingSpeechCursor, &itemName));
TEST(ShowSpeechCursor);
}
{
NAME(strtext("Speech Cursor Blink Period"));
BLINK_PERIOD(&speechCursorBlinkDescriptor);
ITEM(newTimeMenuItem(speechSubmenu, &period, &itemName));
TEST(BlinkingSpeechCursor);
CHANGED(SpeechCursorBlinkPeriod);
}
{
NAME(strtext("Speech Cursor Percent Visible"));
BLINK_VISIBLE(&speechCursorBlinkDescriptor);
ITEM(newBlinkVisibleMenuItem(speechSubmenu, &visible, &itemName));
TEST(BlinkingSpeechCursor);
CHANGED(SpeechCursorBlinkPercentage);
}
}
#endif /* ENABLE_SPEECH_SUPPORT */
{
SUBMENU(timeSubmenu, rootMenu, strtext("Time Presentation"));
{
static const MenuString strings[] = {
[tf24Hour] = {.label=strtext("24 Hour")},
[tf12Hour] = {.label=strtext("12 Hour")},
};
NAME(strtext("Time Format"));
ITEM(newEnumeratedMenuItem(timeSubmenu, &prefs.timeFormat, &itemName, strings));
}
{
static const MenuString strings[] = {
[tsColon] = {.label=strtext("Colon"), ":"},
[tsDot] = {.label=strtext("Dot"), "."},
};
NAME(strtext("Time Separator"));
ITEM(newEnumeratedMenuItem(timeSubmenu, &prefs.timeSeparator, &itemName, strings));
}
{
NAME(strtext("Show Seconds"));
ITEM(newBooleanMenuItem(timeSubmenu, &prefs.showSeconds, &itemName));
}
{
static const MenuString strings[] = {
[dpNone] = {.label=strtext("None")},
[dpBeforeTime] = {.label=strtext("Before Time")},
[dpAfterTime] = {.label=strtext("After Time")},
};
NAME(strtext("Date Position"));
ITEM(newEnumeratedMenuItem(timeSubmenu, &prefs.datePosition, &itemName, strings));
}
{
static const MenuString strings[] = {
[dfYearMonthDay] = {.label=strtext("Year Month Day")},
[dfMonthDayYear] = {.label=strtext("Month Day Year")},
[dfDayMonthYear] = {.label=strtext("Day Month Year")},
};
NAME(strtext("Date Format"));
ITEM(newEnumeratedMenuItem(timeSubmenu, &prefs.dateFormat, &itemName, strings));
TEST(ShowDate);
}
{
static const MenuString strings[] = {
[dsDash] = {.label=strtext("Dash"), "-"},
[dsSlash] = {.label=strtext("Slash"), "/"},
[dsDot] = {.label=strtext("Dot"), "."},
};
NAME(strtext("Date Separator"));
ITEM(newEnumeratedMenuItem(timeSubmenu, &prefs.dateSeparator, &itemName, strings));
TEST(ShowDate);
}
}
{
SUBMENU(statusSubmenu, rootMenu, strtext("Status Cells"));
{
static const MenuString strings[] = {
[spNone] = {.label=strtext("None")},
[spLeft] = {.label=strtext("Left")},
[spRight] = {.label=strtext("Right")},
};
NAME(strtext("Status Position"));
ITEM(newEnumeratedMenuItem(statusSubmenu, &prefs.statusPosition, &itemName, strings));
TEST(StatusPosition);
CHANGED(StatusPosition);
}
{
NAME(strtext("Status Count"));
ITEM(newNumericMenuItem(statusSubmenu, &prefs.statusCount, &itemName, 0, MAX((int)brl.textColumns/2-1, 0), 1, strtext("cells"), NULL));
TEST(StatusCount);
CHANGED(StatusCount);
}
{
static const MenuString strings[] = {
[ssNone] = {.label=strtext("None")},
[ssSpace] = {.label=strtext("Space")},
[ssBlock] = {.label=strtext("Block")},
[ssStatusSide] = {.label=strtext("Status Side")},
[ssTextSide] = {.label=strtext("Text Side")},
};
NAME(strtext("Status Separator"));
ITEM(newEnumeratedMenuItem(statusSubmenu, &prefs.statusSeparator, &itemName, strings));
TEST(StatusSeparator);
CHANGED(StatusSeparator);
}
{
#define STATUS_FIELD_ITEM(number) { ITEM(newStatusFieldMenuItem(statusSubmenu, number, testStatusField##number, changedStatusField##number)); }
STATUS_FIELD_ITEM(1);
STATUS_FIELD_ITEM(2);
STATUS_FIELD_ITEM(3);
STATUS_FIELD_ITEM(4);
STATUS_FIELD_ITEM(5);
STATUS_FIELD_ITEM(6);
STATUS_FIELD_ITEM(7);
STATUS_FIELD_ITEM(8);
STATUS_FIELD_ITEM(9);
#undef STATUS_FIELD_ITEM
}
}
{
SUBMENU(tablesSubmenu, rootMenu, strtext("Braille Tables"));
{
NAME(strtext("Text Table"));
ITEM(newFilesMenuItem(tablesSubmenu, &itemName, opt_tablesDirectory, TEXT_TABLES_SUBDIRECTORY, TEXT_TABLE_EXTENSION, opt_textTable, 0));
CHANGED(TextTable);
SET(textTable);
}
{
NAME(strtext("Contraction Table"));
ITEM(newFilesMenuItem(tablesSubmenu, &itemName, opt_tablesDirectory, CONTRACTION_TABLES_SUBDIRECTORY, CONTRACTION_TABLE_EXTENSION, opt_contractionTable, 1));
CHANGED(ContractionTable);
SET(contractionTable);
}
{
NAME(strtext("Attributes Table"));
ITEM(newFilesMenuItem(tablesSubmenu, &itemName, opt_tablesDirectory, ATTRIBUTES_TABLES_SUBDIRECTORY, ATTRIBUTES_TABLE_EXTENSION, opt_attributesTable, 0));
CHANGED(AttributesTable);
SET(attributesTable);
}
}
{
SUBMENU(profilesSubmenu, rootMenu, strtext("Profiles"));
{
ITEM(newProfileMenuItem(profilesSubmenu, &languageProfile));
CHANGED(LanguageProfile);
SET(languageProfile);
}
}
{
SUBMENU(buildSubmenu, rootMenu, strtext("Build Information"));
setAdvancedSubmenu(buildSubmenu);
{
NAME(strtext("Package Version"));
ITEM(newTextMenuItem(buildSubmenu, &itemName, PACKAGE_VERSION));
}
{
NAME(strtext("Package Revision"));
ITEM(newTextMenuItem(buildSubmenu, &itemName, getRevisionIdentifier()));
}
{
NAME(strtext("Web Site"));
ITEM(newTextMenuItem(buildSubmenu, &itemName, PACKAGE_URL));
}
{
NAME(strtext("Mailing List"));
ITEM(newTextMenuItem(buildSubmenu, &itemName, PACKAGE_BUGREPORT));
}
{
NAME(strtext("Configuration Directory"));
ITEM(newTextMenuItem(buildSubmenu, &itemName, CONFIGURATION_DIRECTORY));
}
{
NAME(strtext("Configuration File"));
ITEM(newTextMenuItem(buildSubmenu, &itemName, CONFIGURATION_FILE));
}
{
NAME(strtext("Updatable Directory"));
ITEM(newTextMenuItem(buildSubmenu, &itemName, UPDATABLE_DIRECTORY));
}
{
NAME(strtext("Preferences File"));
ITEM(newTextMenuItem(buildSubmenu, &itemName, PREFERENCES_FILE));
}
{
NAME(strtext("Writable Directory"));
ITEM(newTextMenuItem(buildSubmenu, &itemName, WRITABLE_DIRECTORY));
}
{
NAME(strtext("Drivers Directory"));
ITEM(newTextMenuItem(buildSubmenu, &itemName, DRIVERS_DIRECTORY));
}
{
NAME(strtext("Tables Directory"));
ITEM(newTextMenuItem(buildSubmenu, &itemName, TABLES_DIRECTORY));
}
{
NAME(strtext("Locale Directory"));
ITEM(newTextMenuItem(buildSubmenu, &itemName, LOCALE_DIRECTORY));
}
}
{
static const MenuString logLevels[] = {
[LOG_EMERG] = {.label=strtext("Emergency")},
[LOG_ALERT] = {.label=strtext("Alert")},
[LOG_CRIT] = {.label=strtext("Critical")},
[LOG_ERR] = {.label=strtext("Error")},
[LOG_WARNING] = {.label=strtext("Warning")},
[LOG_NOTICE] = {.label=strtext("Notice")},
[LOG_INFO] = {.label=strtext("Information")},
[LOG_DEBUG] = {.label=strtext("Debug")},
};
SUBMENU(internalSubmenu, rootMenu, strtext("Internal Parameters"));
setAdvancedSubmenu(internalSubmenu);
{
NAME(strtext("System Log Level"));
ITEM(newEnumeratedMenuItem(internalSubmenu, &systemLogLevel, &itemName, logLevels));
}
{
NAME(strtext("Standard Error Log Level"));
ITEM(newEnumeratedMenuItem(internalSubmenu, &stderrLogLevel, &itemName, logLevels));
}
{
NAME(strtext("Category Log Level"));
ITEM(newEnumeratedMenuItem(internalSubmenu, &categoryLogLevel, &itemName, logLevels));
}
{
SUBMENU(logCategoriesSubmenu, internalSubmenu, strtext("Log Categories"));
setAdvancedSubmenu(logCategoriesSubmenu);
{
LogCategoryIndex category;
for (category=0; category<LOG_CATEGORY_COUNT; category+=1) {
const char *description = getLogCategoryTitle(category);
if (description && *description) {
MenuString *name;
if (!(name = malloc(sizeof(*name)))) goto noItem;
memset(name, 0, sizeof(*name));
name->label = description;
{
ITEM(newBooleanMenuItem(logCategoriesSubmenu, &logCategoryFlags[category], name));
switch (category) {
case LOG_CATEGORY_INDEX(BRAILLE_KEYS):
TEST(InputTable);
break;
case LOG_CATEGORY_INDEX(KEYBOARD_KEYS):
TEST(KeyboardTable);
break;
default:
break;
}
}
}
}
}
}
}
{
SUBMENU(toolsSubmenu, rootMenu, strtext("Tools"));
setAdvancedSubmenu(toolsSubmenu);
{
NAME(strtext("Restart Braille Driver"));
ITEM(newToolMenuItem(toolsSubmenu, &itemName, restartBrailleDriver));
}
#ifdef ENABLE_SPEECH_SUPPORT
{
NAME(strtext("Restart Speech Driver"));
ITEM(newToolMenuItem(toolsSubmenu, &itemName, restartSpeechDriver));
}
#endif /* ENABLE_SPEECH_SUPPORT */
{
NAME(strtext("Restart Screen Driver"));
ITEM(newToolMenuItem(toolsSubmenu, &itemName, restartScreenDriver));
}
}
{
NAME(strtext("Log Messages"));
logMessagesMenu = newSubmenuMenuItem(rootMenu, &itemName);
}
return rootMenu;
noItem:
destroyMenu(rootMenu);
noMenu:
return NULL;
}
Menu *
getPreferencesMenu (void) {
static Menu *menu = NULL;
if (!menu) menu = makePreferencesMenu();
return menu;
}