underline main menu item shortcuts when alt is pressed or main menu is active

This commit is contained in:
Vadim Lopatin 2014-05-08 10:32:45 +04:00
parent 2719aecadb
commit dd0527a698
7 changed files with 145 additions and 29 deletions

View File

@ -296,7 +296,13 @@ enum State : uint {
Parent = 0x10000, // use parent's state
}
/// uppercase unicode character
dchar dcharToUpper(dchar ch) {
// TODO: support non-ascii letters
if (ch >= 'a' && ch <= 'z')
return ch - 'a' + 'A';
return ch;
}
version (Windows) {
immutable char PATH_DELIMITER = '\\';

View File

@ -244,7 +244,7 @@ class Font : RefCountedObject {
charsMeasured = i + 1;
x = tabPosition;
continue;
} else if (ch == '&' && (textFlags & (TextFlag.UnderlineHotKeys | TextFlag.HotKeys))) {
} else if (ch == '&' && (textFlags & (TextFlag.UnderlineHotKeys | TextFlag.HotKeys | TextFlag.UnderlineHotKeysWhenAltPressed))) {
pwidths[i] = x;
continue; // skip '&' in hot key when measuring
}
@ -319,8 +319,8 @@ class Font : RefCountedObject {
int underlineY = y + _baseline + underlineHeight * 2;
for (int i = 0; i < charsMeasured; i++) {
dchar ch = text[i];
if (ch == '&' && (textFlags & (TextFlag.UnderlineHotKeys | TextFlag.HotKeys))) {
if (textFlags & TextFlag.UnderlineHotKeys)
if (ch == '&' && (textFlags & (TextFlag.UnderlineHotKeys | TextFlag.HotKeys | TextFlag.UnderlineHotKeysWhenAltPressed))) {
if (textFlags & (TextFlag.UnderlineHotKeys | TextFlag.UnderlineHotKeysWhenAltPressed))
underline = true; // turn ON underline for hot key
continue; // skip '&' in hot key when measuring
}

View File

@ -32,13 +32,15 @@ private import dlangui.graphics.gldrawbuf;
class Window {
protected int _dx;
protected int _dy;
protected uint _keyboardModifiers;
protected uint _backgroundColor;
protected Widget _mainWidget;
@property uint backgroundColor() { return _backgroundColor; }
@property uint backgroundColor() const { return _backgroundColor; }
@property void backgroundColor(uint color) { _backgroundColor = color; }
@property int width() { return _dx; }
@property int height() { return _dy; }
@property Widget mainWidget() { return _mainWidget; }
@property int width() const { return _dx; }
@property int height() const { return _dy; }
@property uint keyboardModifiers() const { return _keyboardModifiers; }
@property Widget mainWidget() { return _mainWidget; }
@property void mainWidget(Widget widget) {
if (_mainWidget !is null)
_mainWidget.window = null;
@ -244,13 +246,24 @@ class Window {
/// dispatch keyboard event
bool dispatchKeyEvent(KeyEvent event) {
bool res = false;
if (event.action == KeyAction.KeyDown || event.action == KeyAction.KeyUp) {
_keyboardModifiers = event.flags;
if (event.keyCode == KeyCode.ALT || event.keyCode == KeyCode.LALT || event.keyCode == KeyCode.RALT) {
Log.d("ALT key: keyboardModifiers = ", _keyboardModifiers);
if (_mainWidget) {
_mainWidget.invalidate();
res = true;
}
}
}
if (event.action == KeyAction.Text) {
// filter text
if (event.text.length < 1)
return false;
return res;
dchar ch = event.text[0];
if (ch < ' ' || ch == 0x7F) // filter out control symbols
return false;
return res;
}
Widget focus = focusedWidget;
if (focus !is null) {
@ -258,8 +271,8 @@ class Window {
return true; // processed by focused widget
}
if (_mainWidget)
return dispatchKeyEvent(_mainWidget, event);
return false;
return dispatchKeyEvent(_mainWidget, event) || res;
return res;
}
protected bool dispatchMouseEvent(Widget root, MouseEvent event) {

View File

@ -446,17 +446,17 @@ version(USE_SDL) {
if (flags & KMOD_ALT)
res |= KeyFlag.Alt;
if (flags & KMOD_RCTRL)
res |= KeyFlag.RControl;
res |= KeyFlag.RControl | KeyFlag.Control;
if (flags & KMOD_RSHIFT)
res |= KeyFlag.RShift;
res |= KeyFlag.RShift | KeyFlag.Shift;
if (flags & KMOD_RALT)
res |= KeyFlag.RAlt;
res |= KeyFlag.RAlt | KeyFlag.Alt;
if (flags & KMOD_LCTRL)
res |= KeyFlag.LControl;
res |= KeyFlag.LControl | KeyFlag.Control;
if (flags & KMOD_LSHIFT)
res |= KeyFlag.LShift;
res |= KeyFlag.LShift | KeyFlag.Shift;
if (flags & KMOD_LALT)
res |= KeyFlag.LAlt;
res |= KeyFlag.LAlt | KeyFlag.Alt;
return res;
}
@ -471,10 +471,45 @@ version(USE_SDL) {
}
return res;
}
bool processKeyEvent(KeyAction action, uint keyCode, uint flags) {
bool processKeyEvent(KeyAction action, uint keyCode, uint flags) {
Log.d("processKeyEvent ", action, " SDL key=0x", format("%08x", keyCode), " SDL flags=0x", format("%08x", flags));
keyCode = convertKeyCode(keyCode);
flags = convertKeyFlags(flags);
if (action == KeyAction.KeyDown) {
switch(keyCode) {
case KeyCode.ALT:
flags |= KeyFlag.Alt;
break;
case KeyCode.RALT:
flags |= KeyFlag.Alt | KeyFlag.RAlt;
break;
case KeyCode.LALT:
flags |= KeyFlag.Alt | KeyFlag.LAlt;
break;
case KeyCode.CONTROL:
flags |= KeyFlag.Control;
break;
case KeyCode.RCONTROL:
flags |= KeyFlag.Control | KeyFlag.RControl;
break;
case KeyCode.LCONTROL:
flags |= KeyFlag.Control | KeyFlag.LControl;
break;
case KeyCode.SHIFT:
flags |= KeyFlag.Shift;
break;
case KeyCode.RSHIFT:
flags |= KeyFlag.Shift | KeyFlag.RShift;
break;
case KeyCode.LSHIFT:
flags |= KeyFlag.Shift | KeyFlag.LShift;
break;
default:
break;
}
}
Log.d("processKeyEvent ", action, " converted key=0x", format("%08x", keyCode), " converted flags=0x", format("%08x", flags));
bool res = dispatchKeyEvent(new KeyEvent(action, keyCode, flags));
// if ((keyCode & 0x10000) && (keyCode & 0xF000) != 0xF000) {

View File

@ -43,7 +43,33 @@ class MenuItem {
MenuItem subitem(int index) {
return _subitems[index];
}
/// adds submenu item
/// get hotkey character from label (e.g. 'F' for item labeled "&File"), 0 if no hotkey
dchar getHotkey() {
dstring s = label;
dchar ch = 0;
for (int i = 0; i < s.length - 1; i++) {
if (s[i] == '&') {
ch = s[i + 1];
break;
}
}
return dcharToUpper(ch);
}
/// find subitem by hotkey character, returns subitem index, -1 if not found
int findSubitemByHotkey(dchar ch) {
if (!ch)
return -1;
ch = dcharToUpper(ch);
for (int i = 0; i < _subitems.length; i++) {
if (_subitems[i].getHotkey() == ch)
return i;
}
return -1;
}
/// adds submenu item
MenuItem add(MenuItem subitem) {
_subitems ~= subitem;
return this;
@ -85,6 +111,7 @@ class MenuItem {
/// widget to draw menu item
class MenuItemWidget : WidgetGroup {
protected bool _mainMenu;
protected MenuItem _item;
protected ImageWidget _icon;
protected TextWidget _accel;
@ -180,8 +207,9 @@ class MenuItemWidget : WidgetGroup {
}
}
this(MenuItem item) {
this(MenuItem item, bool mainMenu) {
id="menuitem";
_mainMenu = mainMenu;
_item = item;
styleId = "MENU_ITEM";
// icon
@ -193,7 +221,7 @@ class MenuItemWidget : WidgetGroup {
// label
_label = new TextWidget("MENU_LABEL");
_label.text = _item.label;
_label.styleId = "MENU_LABEL";
_label.styleId = _mainMenu ? "MAIN_MENU_LABEL" : "MENU_LABEL";
addChild(_label);
// accelerator
dstring acc = _item.acceleratorText;
@ -230,9 +258,10 @@ class MenuWidgetBase : ListWidget {
WidgetListAdapter adapter = new WidgetListAdapter();
for (int i=0; i < _item.subitemCount; i++) {
MenuItem subitem = _item.subitem(i);
MenuItemWidget widget = new MenuItemWidget(subitem);
MenuItemWidget widget = new MenuItemWidget(subitem, orientation == Orientation.Horizontal);
if (orientation == Orientation.Horizontal)
widget.styleId = "MAIN_MENU_ITEM";
widget.parent = this;
adapter.widgets.add(widget);
}
ownAdapter = adapter;
@ -444,7 +473,16 @@ class MainMenu : MenuWidgetBase {
return true;
}
protected int _menuToggleState;
/// get text flags (bit set of TextFlag enum values)
@property override uint textFlags() {
// override text flags for main menu
if (activated)
return TextFlag.UnderlineHotKeys | TextFlag.HotKeys;
else
return TextFlag.UnderlineHotKeysWhenAltPressed | TextFlag.HotKeys;
}
protected int _menuToggleState;
protected Widget _menuTogglePreviousFocus;

View File

@ -37,6 +37,7 @@ immutable ubyte FONT_STYLE_ITALIC = 0x01;
/// use as widget.layout() param to avoid applying of parent size
immutable int SIZE_UNSPECIFIED = int.max;
immutable uint TEXT_FLAGS_UNSPECIFIED = uint.max;
immutable uint TEXT_FLAGS_USE_PARENT = uint.max - 1;
immutable int FILL_PARENT = int.max - 1;
immutable int WRAP_CONTENT = int.max - 2;
@ -60,8 +61,10 @@ enum TextFlag : uint {
HotKeys = 1,
/// underline hot key when drawing
UnderlineHotKeys = 2,
/// underline hot key when drawing
UnderlineHotKeysWhenAltPressed = 4,
/// underline text when drawing
Underline = 4
Underline = 8
}
class DrawableAttribute {
@ -747,7 +750,7 @@ Theme createDefaultTheme() {
//res.dumpStats();
Style mainMenu = res.createSubstyle("MAIN_MENU").backgroundColor(0xEFEFF2).layoutWidth(FILL_PARENT);
Style mainMenuItem = res.createSubstyle("MAIN_MENU_ITEM").setPadding(4,2,4,2).backgroundImageId("main_menu_item_background");
Style mainMenuItem = res.createSubstyle("MAIN_MENU_ITEM").setPadding(4,2,4,2).backgroundImageId("main_menu_item_background").textFlags(TEXT_FLAGS_USE_PARENT);
Style menuItem = res.createSubstyle("MENU_ITEM").setPadding(4,2,4,2); //.backgroundColor(0xE0E080) ;
menuItem.createState(State.Focused, State.Focused).backgroundColor(0x40C0C000);
menuItem.createState(State.Pressed, State.Pressed).backgroundColor(0x4080C000);
@ -755,6 +758,7 @@ Theme createDefaultTheme() {
menuItem.createState(State.Hovered, State.Hovered).backgroundColor(0xC0FFFF00);
res.createSubstyle("MENU_ICON").setMargins(2,2,2,2).alignment(Align.VCenter|Align.Left);
res.createSubstyle("MENU_LABEL").setMargins(4,2,4,2).alignment(Align.VCenter|Align.Left).textFlags(TextFlag.UnderlineHotKeys);
res.createSubstyle("MAIN_MENU_LABEL").setMargins(4,2,4,2).alignment(Align.VCenter|Align.Left).textFlags(TEXT_FLAGS_USE_PARENT);
res.createSubstyle("MENU_ACCEL").setMargins(4,2,4,2).alignment(Align.VCenter|Align.Left);
Style transparentButtonBackground = res.createSubstyle("TRANSPARENT_BUTTON_BACKGROUND").backgroundImageId("transparent_button_background").setPadding(4,2,4,2); //.backgroundColor(0xE0E080) ;

View File

@ -300,12 +300,32 @@ class Widget {
return this;
}
/// get text flags (bit set of TextFlag enum values)
@property uint textFlags() const { return stateStyle.textFlags; }
@property uint textFlags() {
uint res = stateStyle.textFlags;
if (res == TEXT_FLAGS_USE_PARENT)
if (parent)
res = parent.textFlags;
else
res = 0;
if (res & TextFlag.UnderlineHotKeysWhenAltPressed) {
uint modifiers = 0;
if (window !is null)
modifiers = window.keyboardModifiers;
bool altPressed = (modifiers & (KeyFlag.Alt | KeyFlag.LAlt | KeyFlag.RAlt)) != 0;
if (!altPressed) {
res = (res & ~(TextFlag.UnderlineHotKeysWhenAltPressed | TextFlag.UnderlineHotKeys)) | TextFlag.HotKeys;
} else {
res |= TextFlag.UnderlineHotKeys;
}
}
return res;
}
/// set text flags (bit set of TextFlag enum values)
@property Widget textFlags(uint value) {
ownStyle.textFlags = value;
bool oldHotkeys = (ownStyle.textFlags & (TextFlag.HotKeys | TextFlag.UnderlineHotKeys)) != 0;
bool newHotkeys = (value & (TextFlag.HotKeys | TextFlag.UnderlineHotKeys)) != 0;
bool oldHotkeys = (ownStyle.textFlags & (TextFlag.HotKeys | TextFlag.UnderlineHotKeys | TextFlag.UnderlineHotKeysWhenAltPressed)) != 0;
bool newHotkeys = (value & (TextFlag.HotKeys | TextFlag.UnderlineHotKeys | TextFlag.UnderlineHotKeysWhenAltPressed)) != 0;
if (oldHotkeys != newHotkeys)
requestLayout();
else