diff --git a/Nasal/canvas/gui.nas b/Nasal/canvas/gui.nas index cfc9be928..f614a3984 100644 --- a/Nasal/canvas/gui.nas +++ b/Nasal/canvas/gui.nas @@ -48,6 +48,7 @@ loadWidget("ScrollArea"); loadWidget("Rule"); loadWidget("Slider"); loadWidget("TabWidget"); +loadWidget("ComboBox"); # standard dialogs loadDialog("InputDialog"); diff --git a/Nasal/canvas/gui/Menu.nas b/Nasal/canvas/gui/Menu.nas index b74c95fff..f27d435d9 100644 --- a/Nasal/canvas/gui/Menu.nas +++ b/Nasal/canvas/gui/Menu.nas @@ -52,6 +52,10 @@ gui.MenuItem = { return m; }, + text: func { + return me._text; + }, + setMenu: func(menu) { menu._parent_item = me; menu._canvas_item = me._parent_menu._canvas_item; diff --git a/Nasal/canvas/gui/Widget.nas b/Nasal/canvas/gui/Widget.nas index bceef1804..56798b4e8 100644 --- a/Nasal/canvas/gui/Widget.nas +++ b/Nasal/canvas/gui/Widget.nas @@ -159,7 +159,7 @@ gui.Widget = { # add listener when first binding is added # if this happens before the view is set, we instead do it in _setView below if ((size(me._bindings) == 1) and me._view) { - me.addEventListener("keydown", func(e) me._onKeyPressed(e)); + me._view._root.addEventListener("keydown", func(e) me._onKeyPressed(e)); } }, diff --git a/Nasal/canvas/gui/dialogs/WidgetsFactoryDialog.nas b/Nasal/canvas/gui/dialogs/WidgetsFactoryDialog.nas index 6df559284..fa3a9859e 100644 --- a/Nasal/canvas/gui/dialogs/WidgetsFactoryDialog.nas +++ b/Nasal/canvas/gui/dialogs/WidgetsFactoryDialog.nas @@ -159,7 +159,15 @@ var WidgetsFactoryDialog = { "tick-count" : 10}) .setValue(42); m.numericControlsTab.addItem(m.slider); - + + + m.combo1 = gui.widgets.ComboBox.new(m.tabsContent, style, {}); + m.combo1.addMenuItem("Apples", 0); + m.combo1.addMenuItem("Pears", 1); + m.combo1.addMenuItem("Lemons", 2); + m.combo1.addMenuItem("Oranges", 3); + + m.numericControlsTab.addItem(m.combo1); return m; }, diff --git a/Nasal/canvas/gui/styles/DefaultStyle.nas b/Nasal/canvas/gui/styles/DefaultStyle.nas index 9a563158f..17640f479 100644 --- a/Nasal/canvas/gui/styles/DefaultStyle.nas +++ b/Nasal/canvas/gui/styles/DefaultStyle.nas @@ -973,7 +973,7 @@ DefaultStyle.widgets["menu-bar"] = { } }; -# A button +# A combo-box DefaultStyle.widgets["combo-box"] = { new: func(parent, cfg) { @@ -1129,4 +1129,5 @@ DefaultStyle.widgets.list = { return me; } -} +}; + diff --git a/Nasal/canvas/gui/widgets/ComboBox.nas b/Nasal/canvas/gui/widgets/ComboBox.nas new file mode 100644 index 000000000..70f7c639f --- /dev/null +++ b/Nasal/canvas/gui/widgets/ComboBox.nas @@ -0,0 +1,109 @@ +# SPDX-FileCopyrightText: (C) 2022 James Turner +# SPDX-License-Identifier: GPL-2.0-or-later + +gui.widgets.ComboBox = { + new: func(parent, style, cfg) + { + var cfg = Config.new(cfg); + var m = gui.Widget.new(gui.widgets.ComboBox); + m._focus_policy = m.StrongFocus; +# m._flat = cfg.get("flat", 0); + m._menu = gui.Menu.new(); + m._setView( style.createWidget(parent, cfg.get("type", "combo-box"), cfg) ); + m._items = []; + m._currentIndex = nil; + m._style = style; # cache reference to style for creating items + m._down = 0; + + return m; + }, + + setText: func(text) + { + if( me._view != nil ) + me._view.setText(me, text); + return me; + }, + + show: func() + { + # check if enabled + }, + + menu: func() + { + return me._menu; + }, + +# convenience helper to add simple items + addMenuItem: func(text, value) { + var index = size(me._items); + var item = me.menu().createItem(text, func { me._itemCallback(index);}, {}); + item.menuValue = value; + append(me._items, item); + if (me._currentIndex == nil) { + # select first item added, if we were previously empty + me.setCurrentByIndex(0); + } + }, + +# helper to set the current item by passing in +# a value of an item + setCurrentByValue: func(value) { + var index = 0; + foreach(var i; me._items) { + if (i.menuValue == value) { + setCurrentByIndex(index); + break; + } + + index+=1; + } + + logprint(DEV_WARN, "Canvas.Gui ComboBox: no such value in menu:" ~ value); + }, + + setCurrentByIndex: func(index) { + if (me._currentIndex == index) + return; + + if (index >= size(me._items)) { + logprint(DEV_WARN, "Canvas.Gui ComboBox: invalid index passed to setCUrrentByIndex" ~ index); + return; + } + + me._currentIndex = index; + me._view.setText(me, me._items[index].text()); + }, + + setDown: func(down = 1) + { + if (me._down == down ) + return me; + + me._down = down; + me._onStateChange(); + return me; + }, + +# protected: + _itemCallback: func(index) + { + me.setCurrentByIndex(index); + }, + + _setView: func(view) + { + call(gui.Widget._setView, [view], me); + + var el = view._root; + el.addEventListener("mousedown", func if( me._enabled ) { me.setDown(1); me._openMenu(); }); + el.addEventListener("mouseup", func if( me._enabled ) me.setDown(0)); + el.addEventListener("mouseleave",func me.setDown(0)); + }, + + _openMenu: func + { + me.menu().show(); + } +}; diff --git a/Nasal/canvas/gui/widgets/PopupMenu.nas b/Nasal/canvas/gui/widgets/PopupMenu.nas deleted file mode 100644 index 07b688329..000000000 --- a/Nasal/canvas/gui/widgets/PopupMenu.nas +++ /dev/null @@ -1,61 +0,0 @@ -# SPDX-FileCopyrightText: (C) 2022 James Turner -# SPDX-License-Identifier: GPL-2.0-or-later - -gui.widgets.PopupMenu = { - new: func(parent, style, cfg) - { - var cfg = Config.new(cfg); - var m = gui.Widget.new(gui.widgets.Button); - m._focus_policy = m.StrongFocus; - m._flat = cfg.get("flat", 0); - m._menu = nil; - m._setView( style.createWidget(parent, cfg.get("type", "button"), cfg) ); - - return m; - }, - setText: func(text) - { - if( me._view != nil ) - me._view.setText(me, text); - return me; - }, - - show: func() - { - # check if enabled - }, - - menu: func() - { - if (!me._menu) { - # FIXME pass style - me.menu = gui.widgets.Menu.new(cfg); - } - - return me._menu; - }, - -# convenience helper to add simple items - addMenuItem: func(text, value) { - # FIXME pass style - me.menu().append(gui.widgets.MenuItem.new()); - }, - -# helper to set the current item by passing in -# a value of an item - setCurrentByValue: func(value) { - - - }, - -# protected: - _setView: func(view) - { - call(gui.Widget._setView, [view], me); - - var el = view._root; - el.addEventListener("mousedown", func if( me._enabled ) me.setDown(1)); - el.addEventListener("mouseup", func if( me._enabled ) me.setDown(0)); - el.addEventListener("mouseleave",func me.setDown(0)); - } -}; diff --git a/Nasal/gui/XMLDialog.nas b/Nasal/gui/XMLDialog.nas index 88962cfee..b8c293eda 100644 --- a/Nasal/gui/XMLDialog.nas +++ b/Nasal/gui/XMLDialog.nas @@ -514,7 +514,7 @@ var XMLVRule = }; -var XMLPopupMenu = +var XMLComboBox = { init: func(objectProps) { @@ -524,7 +524,7 @@ var XMLPopupMenu = { # do we support a label or is that a seperate widget? - me._view = cwidgets.PopupMenu.new(viewParent, canvas.style, {}); + me._view = cwidgets.ComboBox.new(viewParent, canvas.style, {}); me._layout = me._view; me._applyLayoutConfig(); me.update(); @@ -585,10 +585,8 @@ var _createCompatObject = func(type) widget = XMLVRule; } - # these are called combos in XML, but are really - # popup menus, no free value entry is possible if (type == "combo") { - widget = XMLPopupMenu; + widget = XMLComboBox; } return gui.xml.Object.new({ diff --git a/gui/styles/AmbianceClassic/widgets/combobox-arrow-disabled.png b/gui/styles/AmbianceClassic/widgets/combobox-arrow-disabled.png new file mode 100644 index 000000000..8680f1cbb Binary files /dev/null and b/gui/styles/AmbianceClassic/widgets/combobox-arrow-disabled.png differ diff --git a/gui/styles/AmbianceClassic/widgets/combobox-arrow.png b/gui/styles/AmbianceClassic/widgets/combobox-arrow.png new file mode 100644 index 000000000..f553eb971 Binary files /dev/null and b/gui/styles/AmbianceClassic/widgets/combobox-arrow.png differ diff --git a/gui/styles/AmbianceClassic/widgets/combobox-button-disabled.png b/gui/styles/AmbianceClassic/widgets/combobox-button-disabled.png new file mode 100644 index 000000000..97c738fda Binary files /dev/null and b/gui/styles/AmbianceClassic/widgets/combobox-button-disabled.png differ diff --git a/gui/styles/AmbianceClassic/widgets/combobox-button-focused.png b/gui/styles/AmbianceClassic/widgets/combobox-button-focused.png new file mode 100644 index 000000000..22289df1c Binary files /dev/null and b/gui/styles/AmbianceClassic/widgets/combobox-button-focused.png differ diff --git a/gui/styles/AmbianceClassic/widgets/combobox-button-pressed-focused.png b/gui/styles/AmbianceClassic/widgets/combobox-button-pressed-focused.png new file mode 100644 index 000000000..5b40af423 Binary files /dev/null and b/gui/styles/AmbianceClassic/widgets/combobox-button-pressed-focused.png differ diff --git a/gui/styles/AmbianceClassic/widgets/combobox-button.png b/gui/styles/AmbianceClassic/widgets/combobox-button.png new file mode 100644 index 000000000..f57e07156 Binary files /dev/null and b/gui/styles/AmbianceClassic/widgets/combobox-button.png differ diff --git a/gui/styles/AmbianceClassic/widgets/combobox-entry-disabled.png b/gui/styles/AmbianceClassic/widgets/combobox-entry-disabled.png new file mode 100644 index 000000000..e72d66ef2 Binary files /dev/null and b/gui/styles/AmbianceClassic/widgets/combobox-entry-disabled.png differ diff --git a/gui/styles/AmbianceClassic/widgets/combobox-entry-focused.png b/gui/styles/AmbianceClassic/widgets/combobox-entry-focused.png new file mode 100644 index 000000000..d6b094a8a Binary files /dev/null and b/gui/styles/AmbianceClassic/widgets/combobox-entry-focused.png differ diff --git a/gui/styles/AmbianceClassic/widgets/combobox-entry.png b/gui/styles/AmbianceClassic/widgets/combobox-entry.png new file mode 100644 index 000000000..ee7a635c3 Binary files /dev/null and b/gui/styles/AmbianceClassic/widgets/combobox-entry.png differ