Sat, 09 Oct 2021 15:23:25 +0300
#331 Keyboard switching
Focus
Rollover
Button size/sizing
--- a/Source/Gorgon/Widgets/Generator.cpp Sat Oct 09 09:27:52 2021 +0300 +++ b/Source/Gorgon/Widgets/Generator.cpp Sat Oct 09 15:23:25 2021 +0300 @@ -2778,7 +2778,7 @@ graph.SetAnchor(UI::Anchor::BottomRight, UI::Anchor::BottomLeft, UI::Anchor::BottomLeft); auto &container = temp.AddPlaceholder(2, UI::ComponentCondition::Always); - container.SetTag(UI::ComponentTemplate::PanelTag); + container.SetTag(UI::ComponentTemplate::ContentsTag); auto &pnltmp = *new UI::Template(makepanel(AssetID::AllExceptTop, true)); container.OwnTemplate(pnltmp);// TODO: replace? container.SetSize(100, 100, UI::Dimension::Percent);
--- a/Source/Gorgon/Widgets/Generator.h Sat Oct 09 09:27:52 2021 +0300 +++ b/Source/Gorgon/Widgets/Generator.h Sat Oct 09 15:23:25 2021 +0300 @@ -235,7 +235,8 @@ Edit, //rectangle with background set to edit FgFilled, BorderFilled, - Caret + Caret, + TabButton, }; enum BorderSide {
--- a/Source/Gorgon/Widgets/TabPanel.h Sat Oct 09 09:27:52 2021 +0300 +++ b/Source/Gorgon/Widgets/TabPanel.h Sat Oct 09 15:23:25 2021 +0300 @@ -9,6 +9,8 @@ #include "../UI/RadioControl.h" #include "../UI/Organizers/Flow.h" +//TODO: Better tab buttons, Overflow options, Disable/hide tab, Tab icons + namespace Gorgon { namespace Widgets { template <class Key_> class basic_TabPanel; @@ -98,11 +100,22 @@ explicit basic_TabPanel(const UI::Template &temp) : ComponentStackComposer(temp, { {UI::ComponentTemplate::ButtonTag, {}}, - {UI::ComponentTemplate::PanelTag, {}}, - }) + {UI::ComponentTemplate::ContentsTag, {}}, + }), + buttonsize(GetUnitWidth() * 3 + GetSpacing() * 2, GetUnitWidth()) { + stack.SetMouseUpEvent([this](auto, auto, auto) { + Focus(); + }); + stack.AddGenerator(UI::ComponentTemplate::ButtonsTag, std::bind(&basic_TabPanel::getbtns, this, std::placeholders::_1)); - radio.ChangedEvent.Register(*this, &basic_TabPanel::Activate); + radio.ChangedEvent.Register([this](const Key_ &key) { + if(!updating) { + Activate(key); + if(HasActiveTab()) + GetActiveTab().Focus(); + } + }); Refresh(); } @@ -119,7 +132,7 @@ /// Create a new tab with the given key and title Tab<Key_> &New(const Key_ &key, const std::string &title) { - auto layertemp = stack.GetTemplate(UI::ComponentTemplate::PanelTag); + auto layertemp = stack.GetTemplate(UI::ComponentTemplate::ContentsTag); if(!layertemp) layertemp = &Registry::Active()[Registry::Panel_Blank]; @@ -135,13 +148,29 @@ tabs.Add(tab); mapping.Add(key, tab); - auto &btn = *new Checkbox(*buttontemp, title); - btn.SetHorizonalAutosize(UI::Autosize::Unit); - buttons.Add(btn); - radio.Add(key, btn); + auto &button = *new Checkbox(*buttontemp, title); + buttons.Add(button); + radio.Add(key, button); + + switch(sizing) { + default: + case Fill: + case Adaptive: + case AutoUnit: + button.SetHorizonalAutosize(true); + button.Resize(buttonsize); + break; + case Auto: + button.SetHorizonalAutosize(UI::Autosize::Automatic); + button.Resize(buttonsize); + break; + case Fixed: + button.Resize(buttonsize); + break; + } if(buttonspnl) - buttonspnl->Add(btn); + buttonspnl->Add(button); if(tabs.GetSize() == 1) { Activate(key); @@ -182,14 +211,18 @@ } /// Remove the tab at the given key - void Remove(const Key_ &key); - - /// Remove all tabs with the supplied title - void RemoveAllOf(const std::string &title); + void Remove(const Key_ &key) { + auto &tab = mapping[key]; + tabs.Remove(tab); + mapping.Remove(key); + delete tab; + } /// Moves the tab at the given key before another tab. If the before tab does not exit, the tab /// will be moved to the end. - void MoveBefore(const Key_ &before, const Key_ &tab); + void MoveBefore(const Key_ &tab, const Key_ &before) { + tabs.MoveBefore(mapping[tab], mapping[before]); + } /// Return the tab with the supplied key Tab<Key_> &operator [](const Key_ &key) { @@ -213,11 +246,16 @@ /// Activates the tab with the key. If key does not exist nothing is done. void Activate(const Key_ &key) { if(mapping.Exists(key)) { - if(radio.Get() != key) + if(radio.Get() != key) { + updating = true; radio.Set(key); + updating = false; + } - mapping[key].Resize(stack.GetTagSize(UI::ComponentTemplate::PanelTag)); - stack.SetWidget(UI::ComponentTemplate::PanelTag, &mapping[key]); + mapping[key].Resize(stack.BoundsOf(stack.IndexOfTag(UI::ComponentTemplate::ContentsTag)).GetSize()); + //stack.SetWidget(UI::ComponentTemplate::ContentsTag, &mapping[key]); + Clear(); + Add(mapping[key]); hasactive = true; } @@ -226,15 +264,55 @@ /// Deactivate the currently active tab. void Deactivate() { radio.Set(Key_{}); - stack.SetWidget(UI::ComponentTemplate::PanelTag, nullptr); + stack.SetWidget(UI::ComponentTemplate::ContentsTag, nullptr); hasactive = false; } /// Activates the next tab - void ActivateNext(); + void ActivateNext() { + long ind = -1; + if(!HasActiveTab()) { + if(tabs.GetCount()) { + ind = 0; + } + } + else { + ind = tabs.FindLocation(GetActiveTab()); + if(ind == tabs.GetCount()-1) { + if(rollover) { + ind = 0; + } + } + else { + ind++; + } + } + + if(ind != -1) + Activate(tabs[ind].GetKey()); + } /// Activates the previous tab - void ActivatePrevious(); + void ActivatePrevious() { + long ind = -1; + if(!HasActiveTab()) { + ind = tabs.GetCount() - 1; + } + else { + ind = tabs.FindLocation(GetActiveTab()); + if(ind == 0) { + if(rollover) { + ind = tabs.GetCount() - 1; + } + } + else { + ind--; + } + } + + if(ind != -1) + Activate(tabs[ind].GetKey()); + } /// Returns if there is an active tab. bool HasActiveTab() const { @@ -258,7 +336,33 @@ } /// Set how the tab buttons will be resized. Default is AutoUnit - void SetButtonSizing(ButtonSizing value); + void SetButtonSizing(ButtonSizing value) { + if(value == sizing) + return; + + sizing = value; + + for(auto &button : buttons) { + switch(sizing) { + default: + case Fill: + case Adaptive: + case AutoUnit: + button.SetHorizonalAutosize(true); + button.Resize(buttonsize); + break; + case Auto: + button.SetHorizonalAutosize(UI::Autosize::Automatic); + button.Resize(buttonsize); + break; + case Fixed: + button.Resize(buttonsize); + break; + } + } + + Refresh(); + } /// Returns how the tab buttons will be resized ButtonSizing GetButtonSizing() const { @@ -297,7 +401,21 @@ /// Sets the size of the tab buttons. The size will be used according /// to ButtonSizing. - void SetButtonSize(const Geometry::Size &size); + void SetButtonSize(const Geometry::Size &value) { + if(buttonsize == value) + return; + + buttonsize = value; + Refresh(); + } + + void SetButtonWidth(int size) { + SetButtonSize(size, buttonsize.Height); + } + + void SetButtonHeight(int size) { + SetButtonSize(buttonsize.Width, size); + } /// Returns the size of the buttons Geometry::Size GetButtonSize() const { @@ -305,7 +423,9 @@ } /// Sets if next or previous tab switches will rollover. Default is false - void SetTabRollover(bool value); + void SetTabRollover(bool value) { + rollover = value; + } /// Returns if next or previous tab switches will rollover. bool GetTabRollover() const { @@ -316,11 +436,14 @@ void Refresh() { int x = 0; for(int i=0; i<tabs.GetCount(); i++) { - buttons[i].SetText(tabs[i].GetTitle()); - buttons[i].Location.X = x; - buttons[i].SetTextWrap(buttontextwrap); - x = buttons[i].GetBounds().Right; - tabs[i].Resize(stack.BoundsOf(stack.IndexOfTag(UI::ComponentTemplate::PanelTag)).GetSize()); + auto &button = buttons[i]; + auto &tab = tabs[i]; + button.SetText(tab.GetTitle()); + button.Location.X = x; + button.SetTextWrap(buttontextwrap); + x = button.GetBounds().Right; + + tab.Resize(stack.BoundsOf(stack.IndexOfTag(UI::ComponentTemplate::ContentsTag)).GetSize()); } if(buttonspnl) { @@ -355,6 +478,37 @@ return tabs.end(); } + bool KeyPressed(Input::Key key, float state) override { + namespace Keycodes = Input::Keyboard::Keycodes; + + if(state == 0) + return false; + + if(key == Keycodes::Tab) { + if(Input::Keyboard::CurrentModifier == Input::Keyboard::Modifier::Ctrl) { + ActivateNext(); + + if(HasActiveTab()) + GetActiveTab().Focus(); + + return true; + } + else if(Input::Keyboard::CurrentModifier == Input::Keyboard::Modifier::ShiftCtrl) { + ActivatePrevious(); + + if(HasActiveTab()) + GetActiveTab().Focus(); + + return true; + } + } + + return false; + } + + + + private: //for key mapping Containers::Hashmap<Key_, Tab<Key_>> mapping; @@ -364,10 +518,11 @@ ButtonSizing sizing = AutoUnit; bool buttontextwrap = false; - ButtonOverflow overflow = Scale; + ButtonOverflow overflow = HideExcess; Geometry::Size buttonsize; //constructor will initialize to 3x1U bool rollover = false; bool hasactive = false; + bool updating = false; Panel *buttonspnl = nullptr; Containers::Collection<Checkbox> buttons;
--- a/Testing/Source/Manual/UI_WidgetTest.cpp Sat Oct 09 09:27:52 2021 +0300 +++ b/Testing/Source/Manual/UI_WidgetTest.cpp Sat Oct 09 15:23:25 2021 +0300 @@ -25,8 +25,12 @@ org << wgt1; + wgt1.Focus(); + wgt1.New("Tab 1", "Tab 1 long text"); wgt1.New("Tab 2"); + wgt1.SetTabRollover(true); + //wgt1.SetButtonTextWrap(true); Widgets::Button btn1("Hey tab 1"); Widgets::Label lbl1("Hey tab 2"); @@ -42,6 +46,7 @@ btn2.Location.Y = 400; btn2.Location.X = Widgets::Registry::Active().GetUnitSize(3) + Widgets::Registry::Active().GetSpacing(); + wgt1.ActivateNext(); app.wind.Run();