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) {
|
||||
VerticalLayout contentLayout = new VerticalLayout();
|
||||
MenuItem mainMenuItems = new MenuItem();
|
||||
MenuItem fileItem = new MenuItem(new Action(1, "&File"d));
|
||||
fileItem.add(new Action(10, "&Open..."d, "document-open", KeyCode.KEY_O, KeyFlag.Control));
|
||||
fileItem.add(new Action(11, "&Save..."d, "document-save", KeyCode.KEY_S, KeyFlag.Control));
|
||||
MenuItem openRecentItem = new MenuItem(new Action(13, "Open recent..."d, "document-open-recent"));
|
||||
MenuItem fileItem = new MenuItem(new Action(1, "MENU_FILE"));
|
||||
fileItem.add(new Action(10, "MENU_FILE_OPEN"c, "document-open", KeyCode.KEY_O, 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, "MENU_FILE_OPEN_RECENT", "document-open-recent"));
|
||||
openRecentItem.add(new Action(100, "&1: File 1"d));
|
||||
openRecentItem.add(new Action(101, "&2: File 2"d));
|
||||
openRecentItem.add(new Action(102, "&3: File 3"d));
|
||||
openRecentItem.add(new Action(103, "&4: File 4"d));
|
||||
openRecentItem.add(new Action(104, "&5: File 5"d));
|
||||
fileItem.add(openRecentItem);
|
||||
fileItem.add(new Action(12, "E&xit"d, "document-close", 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));
|
||||
editItem.add(new Action(EditorActions.Paste, "Paste"d, "edit-paste", KeyCode.KEY_V, KeyFlag.Control));
|
||||
editItem.add(new Action(EditorActions.Cut, "Cut"d, "edit-cut", KeyCode.KEY_X, KeyFlag.Control));
|
||||
editItem.add(new Action(EditorActions.Undo, "Undo"d, "edit-undo", KeyCode.KEY_Z, KeyFlag.Control));
|
||||
editItem.add(new Action(EditorActions.Redo, "Redo"d, "edit-redo", KeyCode.KEY_Y, KeyFlag.Control));
|
||||
editItem.add(new Action(20, "Preferences..."d));
|
||||
fileItem.add(new Action(12, "MENU_FILE_EXIT"c, "document-close"c, KeyCode.KEY_X, KeyFlag.Alt));
|
||||
|
||||
MenuItem editItem = new MenuItem(new Action(2, "MENU_EDIT"));
|
||||
editItem.add(new Action(EditorActions.Copy, "MENU_EDIT_COPY"c, "edit-copy", KeyCode.KEY_C, KeyFlag.Control));
|
||||
editItem.add(new Action(EditorActions.Paste, "MENU_EDIT_PASTE"c, "edit-paste", KeyCode.KEY_V, KeyFlag.Control));
|
||||
editItem.add(new Action(EditorActions.Cut, "MENU_EDIT_CUT"c, "edit-cut", KeyCode.KEY_X, KeyFlag.Control));
|
||||
editItem.add(new Action(EditorActions.Undo, "MENU_EDIT_UNDO"c, "edit-undo", KeyCode.KEY_Z, KeyFlag.Control));
|
||||
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);
|
||||
editPopupItem.add(new Action(EditorActions.Copy, "Copy"d, "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.Cut, "Cut"d, "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.Redo, "Redo"d, "edit-redo", KeyCode.KEY_Y, 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, "MENU_EDIT_PASTE"c, "edit-paste", KeyCode.KEY_V, 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, "MENU_EDIT_UNDO"c, "edit-undo", KeyCode.KEY_Z, 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));
|
||||
windowItem.add(new Action(30, "Preferences"d));
|
||||
MenuItem helpItem = new MenuItem(new Action(4, "Help"d));
|
||||
helpItem.add(new Action(40, "View Help"d));
|
||||
helpItem.add(new Action(41, "About"d));
|
||||
MenuItem viewItem = new MenuItem(new Action(60, "MENU_VIEW"));
|
||||
MenuItem langItem = new MenuItem(new Action(61, "MENU_VIEW_LANGUAGE"));
|
||||
langItem.add((new MenuItem(new Action(611, "MENU_VIEW_LANGUAGE_EN"))).type(MenuItemType.Radio).checked(true));
|
||||
langItem.add((new MenuItem(new Action(612, "MENU_VIEW_LANGUAGE_RU"))).type(MenuItemType.Radio));
|
||||
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(editItem);
|
||||
mainMenuItems.add(windowItem);
|
||||
mainMenuItems.add(viewItem);
|
||||
mainMenuItems.add(windowItem);
|
||||
mainMenuItems.add(helpItem);
|
||||
MainMenu mainMenu = new MainMenu(mainMenuItems);
|
||||
mainMenu.onMenuItemClickListener = delegate(MenuItem item) {
|
||||
|
|
|
@ -28,24 +28,91 @@ import dlangui.widgets.layouts;
|
|||
import dlangui.widgets.lists;
|
||||
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
|
||||
class MenuItem {
|
||||
protected bool _checkable;
|
||||
protected bool _checked;
|
||||
protected bool _enabled;
|
||||
protected MenuItemType _type = MenuItemType.Normal;
|
||||
protected Action _action;
|
||||
protected MenuItem[] _subitems;
|
||||
protected MenuItem _parent;
|
||||
/// item action id, 0 if no action
|
||||
@property int id() { return _action is null ? 0 : _action.id; }
|
||||
/// returns count of submenu items
|
||||
@property int subitemCount() {
|
||||
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
|
||||
MenuItem subitem(int 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
|
||||
dchar getHotkey() {
|
||||
dstring s = label;
|
||||
|
@ -74,12 +141,12 @@ class MenuItem {
|
|||
/// adds submenu item
|
||||
MenuItem add(MenuItem subitem) {
|
||||
_subitems ~= subitem;
|
||||
subitem._parent = this;
|
||||
return this;
|
||||
}
|
||||
/// adds submenu item from action
|
||||
MenuItem add(Action subitemAction) {
|
||||
_subitems ~= new MenuItem(subitemAction);
|
||||
return this;
|
||||
return add(new MenuItem(subitemAction));
|
||||
}
|
||||
/// returns text description for first accelerator of action; null if no accelerators
|
||||
@property dstring acceleratorText() {
|
||||
|
@ -101,7 +168,7 @@ class MenuItem {
|
|||
@property MenuItem action(Action a) { _action = a; return this; }
|
||||
|
||||
/// menu item Enabled flag
|
||||
@property bool enabled() { return _enabled; }
|
||||
@property bool enabled() { return _enabled && type != MenuItemType.Separator; }
|
||||
/// menu item Enabled flag
|
||||
@property MenuItem enabled(bool 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).
|
||||
override void measure(int parentWidth, int parentHeight) {
|
||||
updateState();
|
||||
Rect m = margins;
|
||||
Rect p = padding;
|
||||
// calc size constraints for children
|
||||
|
@ -206,6 +274,17 @@ class MenuItemWidget : WidgetGroup {
|
|||
_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
|
||||
override void onDraw(DrawBuf buf) {
|
||||
if (visibility != Visibility.Visible)
|
||||
|
@ -214,6 +293,7 @@ class MenuItemWidget : WidgetGroup {
|
|||
Rect rc = _pos;
|
||||
applyMargins(rc);
|
||||
applyPadding(rc);
|
||||
updateState();
|
||||
auto saver = ClipRectSaver(buf, rc, alpha);
|
||||
for (int i = 0; i < _children.count; i++) {
|
||||
Widget item = _children.get(i);
|
||||
|
@ -228,11 +308,15 @@ class MenuItemWidget : WidgetGroup {
|
|||
_mainMenu = mainMenu;
|
||||
_item = item;
|
||||
styleId = "MENU_ITEM";
|
||||
if (!item.enabled)
|
||||
resetState(State.Enabled);
|
||||
updateState();
|
||||
string iconId = _item.action.iconId;
|
||||
if (_item.type == MenuItemType.Check)
|
||||
iconId = "btn_check";
|
||||
else if (_item.type == MenuItemType.Radio)
|
||||
iconId = "btn_radio";
|
||||
// icon
|
||||
if (_item.action && _item.action.iconId.length) {
|
||||
_icon = new ImageWidget("MENU_ICON", _item.action.iconId);
|
||||
if (_item.action && iconId.length) {
|
||||
_icon = new ImageWidget("MENU_ICON", iconId);
|
||||
_icon.styleId = "MENU_ICON";
|
||||
_icon.state = State.Parent;
|
||||
addChild(_icon);
|
||||
|
@ -245,11 +329,15 @@ class MenuItemWidget : WidgetGroup {
|
|||
addChild(_label);
|
||||
// accelerator
|
||||
dstring acc = _item.acceleratorText;
|
||||
if (_item.isSubmenu && !mainMenu)
|
||||
acc = "‣"d;
|
||||
if (acc !is null) {
|
||||
_accel = new TextWidget("MENU_ACCEL");
|
||||
_accel.styleId = "MENU_ACCEL";
|
||||
_accel.text = acc;
|
||||
_accel.state = State.Parent;
|
||||
if (_item.isSubmenu && !mainMenu)
|
||||
_accel.alignment = Align.Right | Align.VCenter;
|
||||
addChild(_accel);
|
||||
}
|
||||
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) {
|
||||
debug Log.d("onMenuItem ", item.action.label);
|
||||
if (_openedPopup !is null) {
|
||||
|
@ -424,6 +521,10 @@ class MenuWidgetBase : ListWidget {
|
|||
PopupWidget popup = cast(PopupWidget)parent;
|
||||
if (popup)
|
||||
popup.close();
|
||||
|
||||
handleMenuItemClick(item);
|
||||
|
||||
|
||||
// this pointer now can be invalid - if popup removed
|
||||
if (onMenuItemClickListenerCopy.assigned)
|
||||
if (onMenuItemClickListenerCopy(item))
|
||||
|
@ -566,6 +667,8 @@ class MainMenu : MenuWidgetBase {
|
|||
|
||||
deactivate();
|
||||
|
||||
handleMenuItemClick(item);
|
||||
|
||||
// this pointer now can be invalid - if popup removed
|
||||
if (onMenuItemClickListenerCopy.assigned)
|
||||
if (onMenuItemClickListenerCopy(item))
|
||||
|
|
Loading…
Reference in New Issue