mirror of https://github.com/buggins/dlangui.git
radio button and checkbox menu item types support; i18n of example1
This commit is contained in:
parent
2da47b106a
commit
908fbd396e
|
@ -1 +1,26 @@
|
||||||
EXIT=Exit
|
EXIT=Exit
|
||||||
|
MENU_FILE=&File
|
||||||
|
MENU_FILE_OPEN=&Open
|
||||||
|
MENU_FILE_OPEN_RECENT=Open recent
|
||||||
|
MENU_FILE_SAVE=&Save
|
||||||
|
MENU_FILE_EXIT=E&xit
|
||||||
|
MENU_EDIT=&Edit
|
||||||
|
MENU_EDIT_COPY=&Copy
|
||||||
|
MENU_EDIT_PASTE=&Paste
|
||||||
|
MENU_EDIT_CUT=Cu&t
|
||||||
|
MENU_EDIT_UNDO=&Undo
|
||||||
|
MENU_EDIT_REDO=&Redo
|
||||||
|
MENU_EDIT_PREFERENCES=&Preferences
|
||||||
|
MENU_VIEW=&View
|
||||||
|
MENU_VIEW_LANGUAGE=Interface &Language
|
||||||
|
MENU_VIEW_LANGUAGE_EN=English
|
||||||
|
MENU_VIEW_LANGUAGE_RU=Russian
|
||||||
|
MENU_VIEW_THEME=&Theme
|
||||||
|
MENU_VIEW_THEME_DEFAULT=&Default
|
||||||
|
MENU_VIEW_THEME_CUSTOM1=&Custom 1
|
||||||
|
MENU_WINDOW=&Window
|
||||||
|
MENU_WINDOW_PREFERENCES=&Preferences
|
||||||
|
MENU_HELP=&Help
|
||||||
|
MENU_HELP_VIEW_HELP=&View help
|
||||||
|
MENU_HELP_ABOUT=&About
|
||||||
|
|
||||||
|
|
|
@ -102,40 +102,52 @@ extern (C) int UIAppMain(string[] args) {
|
||||||
static if (true) {
|
static if (true) {
|
||||||
VerticalLayout contentLayout = new VerticalLayout();
|
VerticalLayout contentLayout = new VerticalLayout();
|
||||||
MenuItem mainMenuItems = new MenuItem();
|
MenuItem mainMenuItems = new MenuItem();
|
||||||
MenuItem fileItem = new MenuItem(new Action(1, "&File"d));
|
MenuItem fileItem = new MenuItem(new Action(1, "MENU_FILE"));
|
||||||
fileItem.add(new Action(10, "&Open..."d, "document-open", KeyCode.KEY_O, KeyFlag.Control));
|
fileItem.add(new Action(10, "MENU_FILE_OPEN"c, "document-open", KeyCode.KEY_O, KeyFlag.Control));
|
||||||
fileItem.add(new Action(11, "&Save..."d, "document-save", KeyCode.KEY_S, KeyFlag.Control));
|
fileItem.add(new Action(11, "MENU_FILE_SAVE"c, "document-save", KeyCode.KEY_S, KeyFlag.Control));
|
||||||
MenuItem openRecentItem = new MenuItem(new Action(13, "Open recent..."d, "document-open-recent"));
|
MenuItem openRecentItem = new MenuItem(new Action(13, "MENU_FILE_OPEN_RECENT", "document-open-recent"));
|
||||||
openRecentItem.add(new Action(100, "&1: File 1"d));
|
openRecentItem.add(new Action(100, "&1: File 1"d));
|
||||||
openRecentItem.add(new Action(101, "&2: File 2"d));
|
openRecentItem.add(new Action(101, "&2: File 2"d));
|
||||||
openRecentItem.add(new Action(102, "&3: File 3"d));
|
openRecentItem.add(new Action(102, "&3: File 3"d));
|
||||||
openRecentItem.add(new Action(103, "&4: File 4"d));
|
openRecentItem.add(new Action(103, "&4: File 4"d));
|
||||||
openRecentItem.add(new Action(104, "&5: File 5"d));
|
openRecentItem.add(new Action(104, "&5: File 5"d));
|
||||||
fileItem.add(openRecentItem);
|
fileItem.add(openRecentItem);
|
||||||
fileItem.add(new Action(12, "E&xit"d, "document-close", KeyCode.KEY_X, KeyFlag.Alt));
|
fileItem.add(new Action(12, "MENU_FILE_EXIT"c, "document-close"c, KeyCode.KEY_X, KeyFlag.Alt));
|
||||||
MenuItem editItem = new MenuItem(new Action(2, "&Edit"d));
|
|
||||||
editItem.add(new Action(EditorActions.Copy, "Copy"d, "edit-copy", KeyCode.KEY_C, KeyFlag.Control));
|
MenuItem editItem = new MenuItem(new Action(2, "MENU_EDIT"));
|
||||||
editItem.add(new Action(EditorActions.Paste, "Paste"d, "edit-paste", KeyCode.KEY_V, KeyFlag.Control));
|
editItem.add(new Action(EditorActions.Copy, "MENU_EDIT_COPY"c, "edit-copy", KeyCode.KEY_C, KeyFlag.Control));
|
||||||
editItem.add(new Action(EditorActions.Cut, "Cut"d, "edit-cut", KeyCode.KEY_X, KeyFlag.Control));
|
editItem.add(new Action(EditorActions.Paste, "MENU_EDIT_PASTE"c, "edit-paste", KeyCode.KEY_V, KeyFlag.Control));
|
||||||
editItem.add(new Action(EditorActions.Undo, "Undo"d, "edit-undo", KeyCode.KEY_Z, KeyFlag.Control));
|
editItem.add(new Action(EditorActions.Cut, "MENU_EDIT_CUT"c, "edit-cut", KeyCode.KEY_X, KeyFlag.Control));
|
||||||
editItem.add(new Action(EditorActions.Redo, "Redo"d, "edit-redo", KeyCode.KEY_Y, KeyFlag.Control));
|
editItem.add(new Action(EditorActions.Undo, "MENU_EDIT_UNDO"c, "edit-undo", KeyCode.KEY_Z, KeyFlag.Control));
|
||||||
editItem.add(new Action(20, "Preferences..."d));
|
editItem.add(new Action(EditorActions.Redo, "MENU_EDIT_REDO"c, "edit-redo", KeyCode.KEY_Y, KeyFlag.Control));
|
||||||
|
editItem.add(new Action(20, "MENU_EDIT_PREFERENCES"));
|
||||||
|
|
||||||
MenuItem editPopupItem = new MenuItem(null);
|
MenuItem editPopupItem = new MenuItem(null);
|
||||||
editPopupItem.add(new Action(EditorActions.Copy, "Copy"d, "edit-copy", KeyCode.KEY_C, KeyFlag.Control));
|
editPopupItem.add(new Action(EditorActions.Copy, "MENU_EDIT_COPY"c, "edit-copy", KeyCode.KEY_C, KeyFlag.Control));
|
||||||
editPopupItem.add(new Action(EditorActions.Paste, "Paste"d, "edit-paste", KeyCode.KEY_V, KeyFlag.Control));
|
editPopupItem.add(new Action(EditorActions.Paste, "MENU_EDIT_PASTE"c, "edit-paste", KeyCode.KEY_V, KeyFlag.Control));
|
||||||
editPopupItem.add(new Action(EditorActions.Cut, "Cut"d, "edit-cut", KeyCode.KEY_X, KeyFlag.Control));
|
editPopupItem.add(new Action(EditorActions.Cut, "MENU_EDIT_CUT"c, "edit-cut", KeyCode.KEY_X, KeyFlag.Control));
|
||||||
editPopupItem.add(new Action(EditorActions.Undo, "Undo"d, "edit-undo", KeyCode.KEY_Z, KeyFlag.Control));
|
editPopupItem.add(new Action(EditorActions.Undo, "MENU_EDIT_UNDO"c, "edit-undo", KeyCode.KEY_Z, KeyFlag.Control));
|
||||||
editPopupItem.add(new Action(EditorActions.Redo, "Redo"d, "edit-redo", KeyCode.KEY_Y, KeyFlag.Control));
|
editPopupItem.add(new Action(EditorActions.Redo, "MENU_EDIT_REDO"c, "edit-redo", KeyCode.KEY_Y, KeyFlag.Control));
|
||||||
|
|
||||||
MenuItem windowItem = new MenuItem(new Action(3, "&Window"d));
|
MenuItem viewItem = new MenuItem(new Action(60, "MENU_VIEW"));
|
||||||
windowItem.add(new Action(30, "Preferences"d));
|
MenuItem langItem = new MenuItem(new Action(61, "MENU_VIEW_LANGUAGE"));
|
||||||
MenuItem helpItem = new MenuItem(new Action(4, "Help"d));
|
langItem.add((new MenuItem(new Action(611, "MENU_VIEW_LANGUAGE_EN"))).type(MenuItemType.Radio).checked(true));
|
||||||
helpItem.add(new Action(40, "View Help"d));
|
langItem.add((new MenuItem(new Action(612, "MENU_VIEW_LANGUAGE_RU"))).type(MenuItemType.Radio));
|
||||||
helpItem.add(new Action(41, "About"d));
|
MenuItem themeItem = new MenuItem(new Action(62, "MENU_VIEW_THEME"));
|
||||||
|
themeItem.add((new MenuItem(new Action(621, "MENU_VIEW_THEME_DEFAULT"))).type(MenuItemType.Radio).checked(true));
|
||||||
|
themeItem.add((new MenuItem(new Action(622, "MENU_VIEW_THEME_CUSTOM1"))).type(MenuItemType.Radio));
|
||||||
|
viewItem.add(langItem);
|
||||||
|
viewItem.add(themeItem);
|
||||||
|
|
||||||
|
MenuItem windowItem = new MenuItem(new Action(3, "MENU_WINDOW"));
|
||||||
|
windowItem.add(new Action(30, "MENU_WINDOW_PREFERENCES"));
|
||||||
|
MenuItem helpItem = new MenuItem(new Action(4, "MENU_HELP"));
|
||||||
|
helpItem.add(new Action(40, "MENU_HELP_VIEW_HELP"));
|
||||||
|
helpItem.add(new Action(41, "MENU_HELP_ABOUT"));
|
||||||
mainMenuItems.add(fileItem);
|
mainMenuItems.add(fileItem);
|
||||||
mainMenuItems.add(editItem);
|
mainMenuItems.add(editItem);
|
||||||
mainMenuItems.add(windowItem);
|
mainMenuItems.add(viewItem);
|
||||||
|
mainMenuItems.add(windowItem);
|
||||||
mainMenuItems.add(helpItem);
|
mainMenuItems.add(helpItem);
|
||||||
MainMenu mainMenu = new MainMenu(mainMenuItems);
|
MainMenu mainMenu = new MainMenu(mainMenuItems);
|
||||||
mainMenu.onMenuItemClickListener = delegate(MenuItem item) {
|
mainMenu.onMenuItemClickListener = delegate(MenuItem item) {
|
||||||
|
|
|
@ -28,24 +28,91 @@ import dlangui.widgets.layouts;
|
||||||
import dlangui.widgets.lists;
|
import dlangui.widgets.lists;
|
||||||
import dlangui.widgets.popup;
|
import dlangui.widgets.popup;
|
||||||
|
|
||||||
|
/// menu item type
|
||||||
|
enum MenuItemType {
|
||||||
|
/// normal menu item
|
||||||
|
Normal,
|
||||||
|
/// menu item - checkbox
|
||||||
|
Check,
|
||||||
|
/// menu item - radio button
|
||||||
|
Radio,
|
||||||
|
/// menu separator (horizontal line)
|
||||||
|
Separator,
|
||||||
|
/// submenu - contains child items
|
||||||
|
Submenu
|
||||||
|
}
|
||||||
|
|
||||||
/// menu item properties
|
/// menu item properties
|
||||||
class MenuItem {
|
class MenuItem {
|
||||||
protected bool _checkable;
|
|
||||||
protected bool _checked;
|
protected bool _checked;
|
||||||
protected bool _enabled;
|
protected bool _enabled;
|
||||||
|
protected MenuItemType _type = MenuItemType.Normal;
|
||||||
protected Action _action;
|
protected Action _action;
|
||||||
protected MenuItem[] _subitems;
|
protected MenuItem[] _subitems;
|
||||||
|
protected MenuItem _parent;
|
||||||
/// item action id, 0 if no action
|
/// item action id, 0 if no action
|
||||||
@property int id() { return _action is null ? 0 : _action.id; }
|
@property int id() { return _action is null ? 0 : _action.id; }
|
||||||
/// returns count of submenu items
|
/// returns count of submenu items
|
||||||
@property int subitemCount() {
|
@property int subitemCount() {
|
||||||
return cast(int)_subitems.length;
|
return cast(int)_subitems.length;
|
||||||
}
|
}
|
||||||
|
/// returns subitem index for item, -1 if item is not direct subitem of this
|
||||||
|
@property int subitemIndex(MenuItem item) {
|
||||||
|
for (int i = 0; i < _subitems.length; i++)
|
||||||
|
if (_subitems[i] is item)
|
||||||
|
return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
/// returns submenu item by index
|
/// returns submenu item by index
|
||||||
MenuItem subitem(int index) {
|
MenuItem subitem(int index) {
|
||||||
return _subitems[index];
|
return _subitems[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property MenuItemType type() const {
|
||||||
|
if (_subitems.length > 0) // if there are children, force type to Submenu
|
||||||
|
return MenuItemType.Submenu;
|
||||||
|
return _type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// set new MenuItemType
|
||||||
|
@property MenuItem type(MenuItemType type) {
|
||||||
|
_type = type;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get check for checkbox or radio button item
|
||||||
|
@property bool checked() {
|
||||||
|
return _checked;
|
||||||
|
}
|
||||||
|
/// check radio button with specified index, uncheck other radio buttons in group (group consists of sequence of radio button items; other item type - end of group)
|
||||||
|
protected void checkRadioButton(int index) {
|
||||||
|
// find bounds of group
|
||||||
|
int start = index;
|
||||||
|
int end = index;
|
||||||
|
for (; start > 0 && _subitems[start - 1].type == MenuItemType.Radio; start--) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
for (; end < _subitems.length - 1 && _subitems[end + 1].type == MenuItemType.Radio; end++) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
// check item with specified index, uncheck others
|
||||||
|
for (int i = start; i <= end; i++)
|
||||||
|
_subitems[i]._checked = (i == index);
|
||||||
|
}
|
||||||
|
/// set check for checkbox or radio button item
|
||||||
|
@property MenuItem checked(bool flg) {
|
||||||
|
if (_checked == flg)
|
||||||
|
return this;
|
||||||
|
_checked = flg;
|
||||||
|
if (flg && _parent && type == MenuItemType.Radio) {
|
||||||
|
int index = _parent.subitemIndex(this);
|
||||||
|
if (index >= 0) {
|
||||||
|
_parent.checkRadioButton(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/// get hotkey character from label (e.g. 'F' for item labeled "&File"), 0 if no hotkey
|
/// get hotkey character from label (e.g. 'F' for item labeled "&File"), 0 if no hotkey
|
||||||
dchar getHotkey() {
|
dchar getHotkey() {
|
||||||
dstring s = label;
|
dstring s = label;
|
||||||
|
@ -74,12 +141,12 @@ class MenuItem {
|
||||||
/// adds submenu item
|
/// adds submenu item
|
||||||
MenuItem add(MenuItem subitem) {
|
MenuItem add(MenuItem subitem) {
|
||||||
_subitems ~= subitem;
|
_subitems ~= subitem;
|
||||||
|
subitem._parent = this;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
/// adds submenu item from action
|
/// adds submenu item from action
|
||||||
MenuItem add(Action subitemAction) {
|
MenuItem add(Action subitemAction) {
|
||||||
_subitems ~= new MenuItem(subitemAction);
|
return add(new MenuItem(subitemAction));
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
/// returns text description for first accelerator of action; null if no accelerators
|
/// returns text description for first accelerator of action; null if no accelerators
|
||||||
@property dstring acceleratorText() {
|
@property dstring acceleratorText() {
|
||||||
|
@ -101,7 +168,7 @@ class MenuItem {
|
||||||
@property MenuItem action(Action a) { _action = a; return this; }
|
@property MenuItem action(Action a) { _action = a; return this; }
|
||||||
|
|
||||||
/// menu item Enabled flag
|
/// menu item Enabled flag
|
||||||
@property bool enabled() { return _enabled; }
|
@property bool enabled() { return _enabled && type != MenuItemType.Separator; }
|
||||||
/// menu item Enabled flag
|
/// menu item Enabled flag
|
||||||
@property MenuItem enabled(bool enabled) {
|
@property MenuItem enabled(bool enabled) {
|
||||||
_enabled = enabled;
|
_enabled = enabled;
|
||||||
|
@ -166,6 +233,7 @@ class MenuItemWidget : WidgetGroup {
|
||||||
}
|
}
|
||||||
/// Measure widget according to desired width and height constraints. (Step 1 of two phase layout).
|
/// Measure widget according to desired width and height constraints. (Step 1 of two phase layout).
|
||||||
override void measure(int parentWidth, int parentHeight) {
|
override void measure(int parentWidth, int parentHeight) {
|
||||||
|
updateState();
|
||||||
Rect m = margins;
|
Rect m = margins;
|
||||||
Rect p = padding;
|
Rect p = padding;
|
||||||
// calc size constraints for children
|
// calc size constraints for children
|
||||||
|
@ -206,6 +274,17 @@ class MenuItemWidget : WidgetGroup {
|
||||||
_label.layout(labelRc);
|
_label.layout(labelRc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void updateState() {
|
||||||
|
if (_item.enabled)
|
||||||
|
setState(State.Enabled);
|
||||||
|
else
|
||||||
|
resetState(State.Enabled);
|
||||||
|
if (_item.checked)
|
||||||
|
setState(State.Checked);
|
||||||
|
else
|
||||||
|
resetState(State.Checked);
|
||||||
|
}
|
||||||
|
|
||||||
/// Draw widget at its position to buffer
|
/// Draw widget at its position to buffer
|
||||||
override void onDraw(DrawBuf buf) {
|
override void onDraw(DrawBuf buf) {
|
||||||
if (visibility != Visibility.Visible)
|
if (visibility != Visibility.Visible)
|
||||||
|
@ -214,6 +293,7 @@ class MenuItemWidget : WidgetGroup {
|
||||||
Rect rc = _pos;
|
Rect rc = _pos;
|
||||||
applyMargins(rc);
|
applyMargins(rc);
|
||||||
applyPadding(rc);
|
applyPadding(rc);
|
||||||
|
updateState();
|
||||||
auto saver = ClipRectSaver(buf, rc, alpha);
|
auto saver = ClipRectSaver(buf, rc, alpha);
|
||||||
for (int i = 0; i < _children.count; i++) {
|
for (int i = 0; i < _children.count; i++) {
|
||||||
Widget item = _children.get(i);
|
Widget item = _children.get(i);
|
||||||
|
@ -228,11 +308,15 @@ class MenuItemWidget : WidgetGroup {
|
||||||
_mainMenu = mainMenu;
|
_mainMenu = mainMenu;
|
||||||
_item = item;
|
_item = item;
|
||||||
styleId = "MENU_ITEM";
|
styleId = "MENU_ITEM";
|
||||||
if (!item.enabled)
|
updateState();
|
||||||
resetState(State.Enabled);
|
string iconId = _item.action.iconId;
|
||||||
|
if (_item.type == MenuItemType.Check)
|
||||||
|
iconId = "btn_check";
|
||||||
|
else if (_item.type == MenuItemType.Radio)
|
||||||
|
iconId = "btn_radio";
|
||||||
// icon
|
// icon
|
||||||
if (_item.action && _item.action.iconId.length) {
|
if (_item.action && iconId.length) {
|
||||||
_icon = new ImageWidget("MENU_ICON", _item.action.iconId);
|
_icon = new ImageWidget("MENU_ICON", iconId);
|
||||||
_icon.styleId = "MENU_ICON";
|
_icon.styleId = "MENU_ICON";
|
||||||
_icon.state = State.Parent;
|
_icon.state = State.Parent;
|
||||||
addChild(_icon);
|
addChild(_icon);
|
||||||
|
@ -245,11 +329,15 @@ class MenuItemWidget : WidgetGroup {
|
||||||
addChild(_label);
|
addChild(_label);
|
||||||
// accelerator
|
// accelerator
|
||||||
dstring acc = _item.acceleratorText;
|
dstring acc = _item.acceleratorText;
|
||||||
|
if (_item.isSubmenu && !mainMenu)
|
||||||
|
acc = "‣"d;
|
||||||
if (acc !is null) {
|
if (acc !is null) {
|
||||||
_accel = new TextWidget("MENU_ACCEL");
|
_accel = new TextWidget("MENU_ACCEL");
|
||||||
_accel.styleId = "MENU_ACCEL";
|
_accel.styleId = "MENU_ACCEL";
|
||||||
_accel.text = acc;
|
_accel.text = acc;
|
||||||
_accel.state = State.Parent;
|
_accel.state = State.Parent;
|
||||||
|
if (_item.isSubmenu && !mainMenu)
|
||||||
|
_accel.alignment = Align.Right | Align.VCenter;
|
||||||
addChild(_accel);
|
addChild(_accel);
|
||||||
}
|
}
|
||||||
trackHover = true;
|
trackHover = true;
|
||||||
|
@ -401,6 +489,15 @@ class MenuWidgetBase : ListWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void handleMenuItemClick(MenuItem item) {
|
||||||
|
// precessing for CheckBox and RadioButton menus
|
||||||
|
if (item.type == MenuItemType.Check) {
|
||||||
|
item.checked = !item.checked;
|
||||||
|
} else if (item.type == MenuItemType.Radio) {
|
||||||
|
item.checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void onMenuItem(MenuItem item) {
|
protected void onMenuItem(MenuItem item) {
|
||||||
debug Log.d("onMenuItem ", item.action.label);
|
debug Log.d("onMenuItem ", item.action.label);
|
||||||
if (_openedPopup !is null) {
|
if (_openedPopup !is null) {
|
||||||
|
@ -424,6 +521,10 @@ class MenuWidgetBase : ListWidget {
|
||||||
PopupWidget popup = cast(PopupWidget)parent;
|
PopupWidget popup = cast(PopupWidget)parent;
|
||||||
if (popup)
|
if (popup)
|
||||||
popup.close();
|
popup.close();
|
||||||
|
|
||||||
|
handleMenuItemClick(item);
|
||||||
|
|
||||||
|
|
||||||
// this pointer now can be invalid - if popup removed
|
// this pointer now can be invalid - if popup removed
|
||||||
if (onMenuItemClickListenerCopy.assigned)
|
if (onMenuItemClickListenerCopy.assigned)
|
||||||
if (onMenuItemClickListenerCopy(item))
|
if (onMenuItemClickListenerCopy(item))
|
||||||
|
@ -566,6 +667,8 @@ class MainMenu : MenuWidgetBase {
|
||||||
|
|
||||||
deactivate();
|
deactivate();
|
||||||
|
|
||||||
|
handleMenuItemClick(item);
|
||||||
|
|
||||||
// this pointer now can be invalid - if popup removed
|
// this pointer now can be invalid - if popup removed
|
||||||
if (onMenuItemClickListenerCopy.assigned)
|
if (onMenuItemClickListenerCopy.assigned)
|
||||||
if (onMenuItemClickListenerCopy(item))
|
if (onMenuItemClickListenerCopy(item))
|
||||||
|
|
Loading…
Reference in New Issue