Wed, 07 Oct 2020 16:46:11 +0300
#190 ListItem
--- a/Source/Gorgon/Types.h Wed Oct 07 09:41:58 2020 +0300 +++ b/Source/Gorgon/Types.h Wed Oct 07 16:46:11 2020 +0300 @@ -50,7 +50,7 @@ /// A class that has no members and can be used as placeholder class Empty {}; - /// This enumeration helps with systems that has boolena parameters + /// This enumeration helps with systems that has boolen parameters /// that can be detected automatically, but can also be overriden. enum class YesNoAuto { No = 0, @@ -58,6 +58,14 @@ Auto = 2 }; + /// This enumeration helps with systems that has boolen parameters + /// that can be unset/empty. + enum class YesNoUnset { + No = 0, + Yes = 1, + Unset = 2 + }; + /// Returns the number of bits that are 1 in a number inline int NumberOfSetBits(uint32_t i) { i = i - ((i >> 1) & 0x55555555); @@ -138,6 +146,29 @@ virtual void Update() = 0; }; + /// Marks the parity as Odd or Even. Not every target will support None, + /// but it is provided for places that support it. + enum class Parity { + None = 0, + Odd = 1, + Even = 2, + }; + + /// Defines where an item is located in a list + enum class ItemPosition { + /// Item not in the list + Nowhere = 0, + /// Item is alone in the list + Alone = 1, + /// Item is the first item + First = 2, + /// Does not mean exact middle + Middle = 3, + /// Item is the last item + Last = 4 + }; + + #ifdef DOXYGEN # define ENUMCLASS enum #else
--- a/Source/Gorgon/UI/Template.h Wed Oct 07 09:41:58 2020 +0300 +++ b/Source/Gorgon/UI/Template.h Wed Oct 07 16:46:11 2020 +0300 @@ -219,6 +219,24 @@ /// for the base state. Closed, + /// In lists denotes the item is in odd position + Odd, + + /// In lists denotes the item is in even position + Even, + + /// In a list this denotes the item is at the first place + First, + + /// In a list this denotes the item is somewhere in the middle + Middle, + + /// In a list this denotes the item is at the last place + Last, + + /// In a list this denotes the item alone + Alone, + /// This is for widgets that can be activated, like a count down timer Active, @@ -282,10 +300,11 @@ /// This widget is the default widget of its container Default, - /// This widget is the cancel widget of its container Cancel, + + /// Do not use this value DataEffectStart = Cancel,
--- a/Source/Gorgon/Widgets/Common.h Wed Oct 07 09:41:58 2020 +0300 +++ b/Source/Gorgon/Widgets/Common.h Wed Oct 07 16:46:11 2020 +0300 @@ -18,5 +18,5 @@ } ///@endcond - + } }
--- a/Source/Gorgon/Widgets/Generator.cpp Wed Oct 07 09:41:58 2020 +0300 +++ b/Source/Gorgon/Widgets/Generator.cpp Wed Oct 07 16:46:11 2020 +0300 @@ -1542,4 +1542,107 @@ return temp; } + + UI::Template SimpleGenerator::ListItem() { + Geometry::Size defsize = {WidgetWidth, BorderedWidgetHeight}; + + UI::Template temp; + temp.SetSpacing(Spacing); + temp.SetSize(defsize); + + + temp.AddContainer(0, UI::ComponentCondition::Always) + .AddIndex(1) //border + .AddIndex(2) //boxed content + .AddIndex(9) //bottom sep + ; + + auto setupborder = [&](auto &anim, UI::ComponentCondition condition) { + auto &bg = temp.AddContainer(1, condition); + bg.Background.SetAnimation(anim); + bg.SetSize(100, 100, UI::Dimension::Percent); + bg.SetPositioning(UI::ComponentTemplate::Absolute); + }; + + setupborder(NormalBG(), UI::ComponentCondition::Always); + setupborder(HoverBG(), UI::ComponentCondition::Hover); + setupborder(DownBG(), UI::ComponentCondition::Down); + setupborder(DisabledBG(), UI::ComponentCondition::Disabled); + + auto &boxed = temp.AddContainer(2, UI::ComponentCondition::Always) + .AddIndex(3) //clip + .AddIndex(4) //focus + ; + boxed.SetSize(100, 100, UI::Dimension::Percent); + boxed.SetBorderSize(Border.Width); + boxed.SetPadding(std::max(Border.Radius / 2, Focus.Spacing)); + boxed.SetPositioning(UI::ComponentTemplate::Absolute); + + auto &clip = temp.AddContainer(3, UI::ComponentCondition::Always) + .AddIndex(5) + ; + clip.SetClip(true); + clip.SetPadding(Focus.Spacing + Focus.Width); + clip.SetSize(100, 100, UI::Dimension::Percent); + + //Contents + auto &content = temp.AddContainer(5, UI::ComponentCondition::Always) + .AddIndex(6) //icon + .AddIndex(7) //text + ; + content.SetSize(100, 100, UI::Dimension::Percent); + content.SetSize(100, 100, UI::Dimension::Percent); + content.SetSizing(UI::ComponentTemplate::Automatic); + content.SetPositioning(UI::ComponentTemplate::Absolute); + content.SetAnchor(UI::Anchor::MiddleCenter, UI::Anchor::MiddleCenter, UI::Anchor::MiddleCenter); + + //Icon container + auto &iconcont = temp.AddContainer(6, UI::ComponentCondition::Icon1IsSet) + .AddIndex(8) + ; + iconcont.SetMargin(0, 0, Spacing, 0); + iconcont.SetAnchor(UI::Anchor::MiddleRight, UI::Anchor::MiddleLeft, UI::Anchor::MiddleLeft); + iconcont.SetSizing(UI::ComponentTemplate::Automatic); + + auto setupicon = [&](auto &icon) -> auto& { + icon.SetDataEffect(UI::ComponentTemplate::Icon1); + icon.SetSizing(UI::ComponentTemplate::Automatic); + + return icon; + }; + + setupicon(temp.AddGraphics(8, UI::ComponentCondition::Always)); + setupicon(temp.AddGraphics(8, UI::ComponentCondition::Disabled)).SetColor({1.0f, 0.5f}); + + //Text + auto setuptext = [&](Graphics::RGBA color, UI::ComponentCondition condition) { + auto &txt = temp.AddTextholder(7, condition); + txt.SetRenderer(CenteredFont); + txt.SetColor(color); + txt.SetAnchor(UI::Anchor::MiddleRight, UI::Anchor::MiddleLeft, UI::Anchor::MiddleLeft); + txt.SetDataEffect(UI::ComponentTemplate::Text); + txt.SetSize(100, 100, UI::Dimension::Percent); + txt.SetSizing(UI::ComponentTemplate::ShrinkOnly); + }; + + setuptext(Forecolor.Regular, UI::ComponentCondition::Always); + setuptext(Forecolor.Regular.BlendWith(Forecolor.Hover), UI::ComponentCondition::Hover); + setuptext(Forecolor.Regular.BlendWith(Forecolor.Down), UI::ComponentCondition::Down); + setuptext(Forecolor.Regular.BlendWith(Forecolor.Disabled), UI::ComponentCondition::Disabled); + + setupfocus(temp.AddGraphics(4, UI::ComponentCondition::Focused)); + + auto &sep = temp.AddGraphics(9, UI::ComponentCondition::Always); + sep.SetFillArea(true); + sep.Content.SetAnimation(GrooveBG()); + sep.SetSize({100, UI::Dimension::Percent}, 5); + sep.SetSizing(UI::ComponentTemplate::Fixed); + sep.SetPositioning(UI::ComponentTemplate::Absolute); + sep.SetAnchor(UI::Anchor::None, UI::Anchor::BottomCenter, UI::Anchor::BottomCenter); + + temp.AddIgnored(9, UI::ComponentCondition::Last); + temp.AddIgnored(9, UI::ComponentCondition::Alone); + + return temp; + } }}
--- a/Source/Gorgon/Widgets/Generator.h Wed Oct 07 09:41:58 2020 +0300 +++ b/Source/Gorgon/Widgets/Generator.h Wed Oct 07 16:46:11 2020 +0300 @@ -130,7 +130,7 @@ /// is undefined behaviour. SimpleGenerator() : Generator(false) { } - + /// Initializes the generator void Init(int fontsize = 14, std::string fontname = ""); @@ -181,14 +181,16 @@ virtual UI::Template Layerbox() override; + UI::Template ListItem(); + - virtual int GetSpacing()const override { - return Spacing; - } + virtual int GetSpacing()const override { + return Spacing; + } - virtual int GetEmSize()const override { - return lettervsize.first + lettervsize.second; - } + virtual int GetEmSize()const override { + return lettervsize.first + lettervsize.second; + } Graphics::BitmapRectangleProvider &NormalBorder(); Graphics::BitmapRectangleProvider &HoverBorder();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Source/Gorgon/Widgets/ListItem.cpp Wed Oct 07 16:46:11 2020 +0300 @@ -0,0 +1,207 @@ +#include "ListItem.h" + + +namespace Gorgon { namespace Widgets { + + void ListItem::SetText(const std::string& value) { + text = value; + stack.SetData(UI::ComponentTemplate::Text, value); + } + + + void ListItem::SetIndex(int value) { + index = value; + } + + + void ListItem::SetIcon(const Graphics::Animation &value) { + if(ownicon) { + icon->DeleteAnimation();; + } + delete iconprov; + + icon = &value; + iconprov = nullptr; + stack.SetData(UI::ComponentTemplate::Icon, *icon); + + ownicon = false; + } + + + void ListItem::SetIcon(const Graphics::Bitmap& value){ + SetIcon(dynamic_cast<const Graphics::Animation&>(value)); + } + + + void ListItem::SetIconProvider(const Graphics::AnimationProvider &value) { + auto &anim = value.CreateAnimation(true); + + OwnIcon(anim); + } + + void ListItem::SetIconProvider(Graphics::AnimationProvider &&provider) { + iconprov = &(provider.MoveOutProvider()); + auto &anim = iconprov->CreateAnimation(true); + + OwnIcon(anim); + } + + void ListItem::RemoveIcon() { + if(ownicon) { + icon->DeleteAnimation(); + } + delete iconprov; + + icon = nullptr; + + stack.RemoveData(UI::ComponentTemplate::Icon); + } + + + void ListItem::OwnIcon() { + ownicon = true; + } + + + void ListItem::OwnIcon(const Graphics::Animation &value) { + SetIcon(value); + + ownicon = true; + } + + + void ListItem::OwnIcon(Graphics::Bitmap &&value) { + OwnIcon(*new Graphics::Bitmap(std::move(value))); + } + + + bool ListItem::Activate() { + ToggleEvent(); + + return true; + } + + + void ListItem::SetFocusState(bool value) { + if(value == focus) + return; + + focus = value; + + if(value) { + stack.AddCondition(UI::ComponentCondition::Focused); + } + else { + stack.RemoveCondition(UI::ComponentCondition::Focused); + } + } + + + void ListItem::SetSelected(bool value) { + if(value == selected) + return; + + selected = value; + + if(value) { + stack.AddCondition(UI::ComponentCondition::State2); + } + else { + stack.RemoveCondition(UI::ComponentCondition::State2); + } + } + + + void ListItem::SetParity(Parity value) { + if(value == parity) + return; + + if(parity == Parity::Odd) { + stack.RemoveCondition(UI::ComponentCondition::Odd); + } + else if(parity == Parity::Even) { + stack.RemoveCondition(UI::ComponentCondition::Even); + } + + parity = value; + + if(value == Parity::Odd) { + stack.AddCondition(UI::ComponentCondition::Odd); + } + else if(value == Parity::Even) { + stack.AddCondition(UI::ComponentCondition::Even); + } + } + + + void ListItem::SetOpened(YesNoUnset value) { + if(value == opened) + return; + + if(opened == YesNoUnset::Yes) { + stack.RemoveCondition(UI::ComponentCondition::Opened); + } + else if(opened == YesNoUnset::No) { + stack.RemoveCondition(UI::ComponentCondition::Closed); + } + + opened = value; + + if(value == YesNoUnset::Yes) { + stack.AddCondition(UI::ComponentCondition::Opened); + } + else if(value == YesNoUnset::No) { + stack.AddCondition(UI::ComponentCondition::Closed); + } + + } + + + void ListItem::SetPosition(ItemPosition value) { + if(value == position) + return; + + switch(position) { + case ItemPosition::Alone: + stack.RemoveCondition(UI::ComponentCondition::Alone); + break; + case ItemPosition::First: + stack.RemoveCondition(UI::ComponentCondition::First); + break; + case ItemPosition::Middle: + stack.RemoveCondition(UI::ComponentCondition::Middle); + break; + case ItemPosition::Last: + stack.RemoveCondition(UI::ComponentCondition::Last); + break; + default: + ; //nothing else needs to be done + } + + position = value; + + switch(value) { + case ItemPosition::Alone: + stack.AddCondition(UI::ComponentCondition::Alone); + break; + case ItemPosition::First: + stack.AddCondition(UI::ComponentCondition::First); + break; + case ItemPosition::Middle: + stack.AddCondition(UI::ComponentCondition::Middle); + break; + case ItemPosition::Last: + stack.AddCondition(UI::ComponentCondition::Last); + break; + default: + ; //nothing else needs to be done + } + } + + + bool ListItem::allowfocus() const { + return false; + } + + +} }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Source/Gorgon/Widgets/ListItem.h Wed Oct 07 16:46:11 2020 +0300 @@ -0,0 +1,197 @@ +#pragma once + +#include "../UI/ComponentStackWidget.h" +#include "../Property.h" +#include "Registry.h" +#include "../Graphics/Bitmap.h" + +#include <limits> + +namespace Gorgon { namespace Widgets { + + /** + * This widget is designed to be used by Listbox, Table, Grid and + * Treeview. It can be used separately, however, it has minimal + * functionality. The rest of the functionality is provided by the + * host widget. + * + * This widget is meant to be used in listboxes to display the contents. + * ListItem only supports strings; therefore, conversion is necessary at + * the Listbox side. ListboxItem does not perform any operation by itself. + * All state changes should be facilitated by the listbox. They cannot be + * focused, focus state is faked. State changes apart from hover/down/ + * disabled are not automatic. This item will not handle keys and is not + * meant to have focus. Finally, apart from the inherited properties, this + * widget does not feature any properties. + * + * ClickEvent will be raise when the widget is clicked. This event will be + * raised first if the widget will be toggled too. Toggle event will be + * called depending on the template. If the template features ToggleTag, + * only clicking ToggleTag component will raise this event. Otherwise, every + * click will raise it. Even if ToggleTag component is clicked, ClickEvent + * will be fired first. + */ + class ListItem : public UI::ComponentStackWidget { + public: + + /// Constructor requires template. ListItem + ListItem(const UI::Template &temp) : + UI::ComponentStackWidget(temp) + { + stack.HandleMouse(); + } + + /// Changes the text displayed. Depending on the template, text might be + /// overwritten by icon. + void SetText(const std::string &value); + + /// Returns the currently displayed text. + std::string GetText() const { + return text; + } + + + /// Sets the index of the ListItem in the Listbox + void SetIndex(int value); + + /// Returns the index of the Item in the Listbox + int GetIndex() const { + return index; + } + + + /// Changes the icon on the label. The ownership of the bitmap + /// is not transferred. If you wish the bitmap to be destroyed + /// with the label, use OwnIcon instead. + void SetIcon(const Graphics::Bitmap &value); + + /// Changes the icon on the label. The ownership of the animation + /// is not transferred. If you wish the animation to be destroyed + /// with the label, use OwnIcon instead. + void SetIcon(const Graphics::Animation &value); + + /// Changes the icon on the label. This will create a new animation + /// from the given provider and will own the resultant animation. + void SetIconProvider(const Graphics::AnimationProvider &value); + + /// Changes the icon on the label. This will move in the provider, + /// create a new animation and own both the provider and the animation + void SetIconProvider(Graphics::AnimationProvider &&provider); + + /// Removes the icon on the label + void RemoveIcon(); + + /// Returns if the label has an icon + bool HasIcon() const { + return icon != nullptr; + } + + /// Returns the icon on the label. If the label does not have an + /// icon, this function will throw + const Graphics::Animation &GetIcon() const { + if(!HasIcon()) + throw std::runtime_error("This widget has no icon."); + + return *icon; + } + + /// Transfers the ownership of the current icon. + void OwnIcon(); + + /// Sets the icon while transferring the ownership + void OwnIcon(const Graphics::Animation &value); + + /// Moves the given animation to the icon of the label + void OwnIcon(Graphics::Bitmap &&value); + + + /// Sets the focus state of the widget. This is different from actual + /// focus where the widget will receive keyevents. + void SetFocusState(bool value); + + /// Returns the current focus state of the widget. + bool GetFocusState() const { + return focus; + } + + + /// Sets selection status of the widget. Depending on the template, + /// selected status might invert colors or display checkbox, + /// radiobutton or similar indication that the item is selected. + void SetSelected(bool value); + + /// Return selection status. + bool GetSelected() const { + return selected; + } + + + /// Set odd/even parity of the widget. Depending on the template this + /// might not have any effect at all. + void SetParity(Parity value); + + /// Returns the odd/even parity. + Parity GetParity() const { + return parity; + } + + + /// Sets whether the item is opened and displaying subitems. This will + /// not actually display any subitems, but only an indication. Depending + /// on the template No might display + icon, Yes might display - icon. + /// Setting this value to Unset will ensure no indication will be + /// displayed. + void SetOpened(YesNoUnset value); + + /// Returns whether the item is opened and displaying subitems. + YesNoUnset GetOpened() const { + return opened; + } + + /// Sets the position of this item in the list. Depending on the + /// template this might display visual cues or used as a way to connect + /// treeview items to their parent. + void SetPosition(ItemPosition value); + + /// Returns the position of this item in the list. This is not automated + ItemPosition GetPosition() const { + return position; + } + + virtual bool Activate() override; + + /// Fired when the item is clicked. This includes clicks to toggle area. + Event<ListItem> ClickEvent = Event<ListItem> {this}; + + /// If template has a ToggleTag, this will be raised only if that + /// component is clicked. Otherwise this will be raised when anywhere is + /// clicked. This event will be fired after ClickEvent. Only case when + /// toggle event will not be triggered is when this widget gets activated + Event<ListItem> ToggleEvent = Event<ListItem> {this}; + + + protected: + virtual bool allowfocus() const override; + + private: + std::string text; + + int index = 0; + + const Graphics::Animation *icon = nullptr; + const Graphics::AnimationProvider *iconprov = nullptr; + bool ownicon = false; + + bool focus = false; + + bool selected = false; + + Parity parity = Parity::None; + + YesNoUnset opened = YesNoUnset::Unset; + + ItemPosition position = ItemPosition::Nowhere; + + }; + +} }
--- a/Source/Gorgon/Widgets/dir.cmake Wed Oct 07 09:41:58 2020 +0300 +++ b/Source/Gorgon/Widgets/dir.cmake Wed Oct 07 16:46:11 2020 +0300 @@ -23,6 +23,9 @@ Layerbox.h Layerbox.cpp + ListItem.h + ListItem.cpp + Panel.h Panel.cpp
--- a/Testing/Source/Manual/UI_Generate.cpp Wed Oct 07 09:41:58 2020 +0300 +++ b/Testing/Source/Manual/UI_Generate.cpp Wed Oct 07 16:46:11 2020 +0300 @@ -14,6 +14,7 @@ #include <Gorgon/Widgets/Progressbar.h> #include <Gorgon/Widgets/Scrollbar.h> #include <Gorgon/Widgets/Composer.h> +#include <Gorgon/Widgets/ListItem.h> #include <Gorgon/UI/RadioControl.h> #include <Gorgon/UI/Organizers/List.h> #include <Gorgon/Graphics/BlankImage.h> @@ -46,21 +47,6 @@ return max.substr(0, (max.length() - min.length()) * value + min.length()); } -class LabelInput : public Widgets::Composer { -public: - LabelInput() { - Resize(l.Size.Width, t.Size.Height); - Add(l); - Add(t); - l.Size.Width = t.Size.Width; - t.Location.X = l.Size.Width + Widgets::Registry::Active().GetSpacing(); - l.Location.Y = (t.Size.Height-l.Size.Height) / 2; - } - - Widgets::Label l; - Widgets::Textbox t; -}; - int main() { basic_Application<UI::Window> app("uitest", "UI Generator Test", helptext, 1, 0x80); @@ -95,7 +81,7 @@ radio.SetColumns(2); - Gorgon::Widgets::Sizefbox input; + Gorgon::Widgets::Textbox input; Gorgon::Widgets::Checkbox chk("Black",Gorgon::Widgets::Registry::Checkbox_Regular); Gorgon::Widgets::Checkbox chk2("Lattej"); @@ -192,12 +178,6 @@ addme(blank, sizef); - LabelInput li; - li.l.Text = "Some input: "; - li.t = "hello"; - - addme(blank, li); - /*Widgets::Progressor<std::string, StringDiv, StringVal, Gorgon::TextualProperty> bar2; bar2.Maximum = "Hello world";