ItemListBox with ItemEntry based on StaticImage

For help with anything that CEGUI doesn't offer straight out-of-the-box, e.g.:
- Implementation of new features, such as new Core classes, widgets, WindowRenderers, etc. ...
- Modification of any existing features for specific purposes
- Integration of CEGUI in new engines or frameworks and writing of new plugins (Renderer, Parser, ...) or modules

Moderators: CEGUI MVP, CEGUI Team

Guest

ItemListBox with ItemEntry based on StaticImage

Postby Guest » Fri Mar 23, 2007 13:10

What am I doing wrong? There isn't much help regarding the new ItemListBox control.

Code: Select all

CEGUI::Imageset* tstSet = CEGUI::ImagesetManager::getSingleton().createImagesetFromImageFile("ImageForStaticImage", "button-check.png");
CEGUI::ItemListbox* tst = static_cast<CEGUI::ItemListbox*> (wmgr.getWindow("lstTest"));
CEGUI::ItemEntry* newItem = new CEGUI::ItemEntry("TaharezLook/StaticImage","MyNewItem");
newItem->setProperty("Image", "set:ImageForStaticImage image:full_image");
tst->addItem(newItem);


I get a runtime error saying that there is no Image property.

User avatar
Levia
Quite a regular
Quite a regular
Posts: 83
Joined: Mon May 22, 2006 18:25
Location: Bergen op zoom, The Netherlands
Contact:

Postby Levia » Fri Mar 23, 2007 13:13

ItemEntry is a base class, it only has a few property's. I think ItemEntry is meant for custom items.
Image
Image

User avatar
scriptkid
Home away from home
Home away from home
Posts: 1178
Joined: Wed Jan 12, 2005 12:06
Location: The Hague, The Netherlands
Contact:

Postby scriptkid » Fri Mar 23, 2007 13:22

Hi,

ItemEntries are not even related to Listboxes ;) They are the base class for menuitems. What you need for listboxes (or comboboxes) is the ListboxTextItem. However that widget has no Image property. But you can set an image which should be used when you select the item:

Code: Select all

item.setSelectionBrushImage("WindowsLook", "Background")


for example. Make sure to make a call to 'setSelectionColours' as well if your default background is white. Otherwise you won't see text.

HTH.

Guest

Postby Guest » Fri Mar 23, 2007 13:38

scriptkid: I am talking about the new listbox, ItemListBox. ListBoxTextItem is for the old ListBox. At least I thought so. I am trying to list images in the ItemListBox. I thought the new 0.5 feature was capable of this.

User avatar
scriptkid
Home away from home
Home away from home
Posts: 1178
Joined: Wed Jan 12, 2005 12:06
Location: The Hague, The Netherlands
Contact:

Postby scriptkid » Fri Mar 23, 2007 14:11

You are right about the ListBox, which is the elder version. I still use that one myself so never noticed ;)

ListBoxItem (and its subclasses) are for 0.5 as well. If you look at the .scheme file(s), you will see that this widget maps to a falagard ItemEntry type. So you can add ListBoxTextItems to your ItemListBox. (I just verified this in the editor.)

Good luck!

Rackle
CEGUI Team (Retired)
Posts: 534
Joined: Mon Jan 16, 2006 11:59
Location: Montréal

Postby Rackle » Fri Mar 23, 2007 17:28

This is a work in progress (aka an Wiki entry in the making). The following works (only has code for the listbox so far) but will require a main.cpp (use the one from WidgetGalore and replace the #include) as well as modifying the resource group directories.

Basically I derived from ListboxTextItem, used a constructor with the same parameters that only calls the ListboxTextItem constructor, added a method to specify an image, and reused the draw functions such that they first draw the text (if any) and then draw the image (if any).

The end result is a class that handles both text AND images:

EDIT: Moved the code to a post below, which now accepts a CEGUI::Window.
Last edited by Rackle on Sun Mar 25, 2007 20:46, edited 1 time in total.

Rackle
CEGUI Team (Retired)
Posts: 534
Joined: Mon Jan 16, 2006 11:59
Location: Montréal

Postby Rackle » Fri Mar 23, 2007 19:03

Now that I think about it, I'll probably write a generic ListboxItem class that can handle any type of object, including a multi-widget item (imagine the possibility of displaying some text, an image, a checkbox, a pushbutton, etc all within the same listbox item). So rather than accepting an Image* the new class would accept a Window*. With what I've done so far it shouldn't be too complicated.

Rackle
CEGUI Team (Retired)
Posts: 534
Joined: Mon Jan 16, 2006 11:59
Location: Montréal

Postby Rackle » Sun Mar 25, 2007 21:02

Here's as far as I got along this line of thinking.

I created a listbox item (DefaultWindow) in the .layout, which is then placed within the listbox. What's needed is a clone() function to create multiple instances of that window.

The ListboxItemWindow helper class has a getPixelSize() function (used by CEGUI::Listbox class) to return the dimensions of the listbox item (i.e. the window that I'm using). Since that window was designed (within the Layout Editor) using relative coordinates it had to be parented to the listbox and redimensioned; this happens within the setListboxItem() function.

The draw() function simply moves the window to the proper position within the Listbox. I'm not drawing nor recalling the image from the cache as the existing window drawing code is already taking care of that; all that's needed is to properly position the window. One difficulty is that the window can appear below the horizontal scrollbar that appears at the bottom of the Listbox.

There's a problem with widgets that respond to mouse clicks, such as a checkbox or a pushbutton; these will prevent the listbox from responding to a mouse click in order to highlight the selected listbox item. To palliate this I had those widgets subscribe to the onListboxItemWindowChildClicked() function when clicked. That function figures out who the parent window is (the window being used as a listbox item) and whether that list item is currently selected. If not then a call is made to the listbox to select it. To make this work I used the "text" of both the window and the list item.

This works but does not yield the result I wished for. To show the window as highlighted I set its alpha to zero and checked each child of that window to not inherit the alpha from its parent. This allows the highlight to pass through the empty region of the window. A better highlight would be blended on top of the window (and on top of every widget).

That's it for now. I'm not perfectly happy with the result so won't wiki this.

Code: Select all

#ifndef _ListboxItemWindow_Demo_h_
#define _ListboxItemWindow_Demo_h_

/* Notes:
   Used a DefaultWindow as the base ListItem.
   This base has an alpha of 0.0f, in order to show the highlight through.
   On top of the base are various widgets, each set to NOT inherit the alpha.
*/

#include "CEGuiSample.h"
#include "CEGUI.h"
#include "CEGUIDefaultResourceProvider.h"


class ListboxItemWindow : public CEGUI::ListboxItem
{
public:
   ListboxItemWindow(const CEGUI::String& text, CEGUI::uint item_id = 0, void* item_data = 0, bool disabled = false, bool auto_delete = true)
      : ListboxItem(text, item_id, item_data, disabled, auto_delete),
        d_window(0)
   {
   }

   //----------------------------------------------
   // Specify the window to use as a list item within a listbox
   void setListboxItem(CEGUI::Window* listbox,
                  CEGUI::Window* window,
                  const CEGUI::UDim& height = CEGUI::UDim(0.0f, 20.0f),
                  const CEGUI::UDim& width = CEGUI::UDim(0.9f, 0.5f))
   {
      d_window = window;

      // The window text must match the ListboxItem text in order to match the two together.
      // Used to determine whether the window list item needs to be selected, when clicking
      // on one of its children that consumes the listbox "selection" event i.e. clicking on
      // the listbox.
      d_window->setText(d_itemText);

      // Adding the window as a child makes it easier to handle (ie always on top of the listbox)
      listbox->addChildWindow( d_window->getName() );

      // Redimention the window height.
      d_window->setHeight(height);

      // Redimention the window width.
      d_window->setWidth(width);
   }

   //----------------------------------------------
   // Return the dimension of this list item i.e. the window size
   CEGUI::Size getPixelSize(void) const
   {
      CEGUI::Size size(0.0f, 0.0f);
      if(d_window)
      {
         size = d_window->getPixelSize();
      }
      return size;
   }

   //----------------------------------------------
    void draw(const CEGUI::Vector3& position, float alpha, const CEGUI::Rect& clipper) const
   {
      // Draw the window or, actually, move it to the proper location
      if (d_window != 0)
      {
         CEGUI::UVector2 windowPos;
         windowPos.d_x.d_scale  = 0.0f;
         windowPos.d_x.d_offset = position.d_x;
         windowPos.d_y.d_scale  = 0.0f;
         windowPos.d_y.d_offset = position.d_y;
         d_window->setPosition( windowPos );
      }

      // Draw the highlight
      if (d_selected && (d_selectBrush != 0))
      {
         d_selectBrush->draw(clipper, position.d_z, clipper, getModulateAlphaColourRect(d_selectCols, alpha));
      }

   }

   //----------------------------------------------
    void draw(CEGUI::RenderCache& cache,const CEGUI::Rect& targetRect, float zBase,  float alpha, const CEGUI::Rect* clipper) const
   {
      // Draw the window or, actually, move it to the proper location
      if (d_window != 0)
      {
         CEGUI::UVector2 windowPos;
         windowPos.d_x.d_scale  = 0.0f;
         windowPos.d_x.d_offset = targetRect.d_left;
         windowPos.d_y.d_scale  = 0.0f;
         windowPos.d_y.d_offset = targetRect.d_top;
         d_window->setPosition( windowPos );
      }

      // Draw the highlight
      if (d_selected && d_selectBrush != 0)
      {
         cache.cacheImage(*d_selectBrush, targetRect, zBase, getModulateAlphaColourRect(d_selectCols, alpha), clipper);
      }
   }

private:
   CEGUI::Window* d_window;
};

//-----------------------------------------------------------------------------
class DemoSample : public CEGuiSample
{
public:
    bool initialiseSample()
   {
      using namespace CEGUI;

      // The executable is stored within <cegui>/bin
      // The following will change the location of the datafiles from their default of
      // ../datafiles (which works well for samples) to <cegui>/samples/datafiles
      DefaultResourceProvider* rp = reinterpret_cast<DefaultResourceProvider*>(System::getSingleton().getResourceProvider());
      rp->setResourceGroupDirectory("fonts",         "../samples/datafiles/fonts/");
      rp->setResourceGroupDirectory("imagesets",      "../samples/datafiles/imagesets/");
      rp->setResourceGroupDirectory("layouts",      "c:/programming/_Projects/CeguiTestBed/");
      rp->setResourceGroupDirectory("looknfeels",      "../samples/datafiles/looknfeel/");
      rp->setResourceGroupDirectory("lua_scripts",   "../samples/datafiles/lua_scripts/");
      rp->setResourceGroupDirectory("schemes",      "../samples/datafiles/schemes/");
      Font::setDefaultResourceGroup("fonts");
      Imageset::setDefaultResourceGroup("imagesets");
      WindowManager::setDefaultResourceGroup("layouts");
      WidgetLookManager::setDefaultResourceGroup("looknfeels");
      ScriptModule::setDefaultResourceGroup("lua_scripts");
      Scheme::setDefaultResourceGroup("schemes");

      try
      {
         // Retrieve the window manager
         WindowManager& winMgr = WindowManager::getSingleton();

         // Load the TaharezLook scheme and set up the default mouse cursor and font
         SchemeManager::getSingleton().loadScheme("TaharezLook.scheme");
         System::getSingleton().setDefaultMouseCursor("TaharezLook", "MouseArrow");
         FontManager::getSingleton().createFont("Commonwealth-10.font");

         // Set the GUI Sheet
         Window* sheet = winMgr.createWindow("DefaultWindow", "root_wnd");
         System::getSingleton().setGUISheet(sheet);

         // Load a layout
         Window* guiLayout = winMgr.loadWindowLayout("ListItemWindow.layout");
         sheet->addChildWindow(guiLayout);



         /* Listbox */
         Listbox* listbox = static_cast<Listbox*>(winMgr.getWindow("ListWindow/Listbox"));
         listbox->setMultiselectEnabled(false);
         ListboxTextItem* itemListbox = new ListboxTextItem("Value A", 1);
            itemListbox->setSelectionBrushImage("TaharezLook", "MultiListSelectionBrush");
            listbox->addItem(itemListbox);
         itemListbox = new ListboxTextItem("Value B", 2);
            itemListbox->setSelectionBrushImage("TaharezLook", "MultiListSelectionBrush");
            listbox->addItem(itemListbox);
         itemListbox = new ListboxTextItem("Value C", 3);
            itemListbox->setSelectionBrushImage("TaharezLook", "MultiListSelectionBrush");
            listbox->addItem(itemListbox);
         itemListbox = new ListboxTextItem("Value D", 4);
            itemListbox->setSelectionBrushImage("TaharezLook", "MultiListSelectionBrush");
            listbox->addItem(itemListbox);
         listbox->setItemSelectState(itemListbox, true);
         listbox->ensureItemIsVisible(itemListbox);
         uint valueListbox = listbox->getFirstSelectedItem()->getID(); // Retrieve the ID of the selected listbox item




         ListboxItemWindow* listboxItemWindow;
         listboxItemWindow = new ListboxItemWindow("Window List Item", 5);
         ImagesetManager::getSingleton().createImagesetFromImageFile("ImageForStaticImage", "GPN-2000-001437.tga");
         DefaultWindow* staticImage = static_cast<DefaultWindow*>(winMgr.getWindow("ListboxItem/Picture"));
         staticImage->setProperty("Image", "set:ImageForStaticImage image:full_image"); // "full_image" is a default name from CEGUIImageset::Imageset()
         Checkbox* checkbox = static_cast<Checkbox*>(winMgr.getWindow("ListboxItem/Checkbox"));
         checkbox->subscribeEvent(CEGUI::Checkbox::EventCheckStateChanged, CEGUI::Event::Subscriber(&DemoSample::onListboxItemWindowChildClicked, this));
         PushButton* pushbuttom = static_cast<PushButton*>(winMgr.getWindow("ListboxItem/PushButton"));
         pushbuttom->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&DemoSample::onListboxItemWindowChildClicked, this));
         listboxItemWindow->setSelectionBrushImage("TaharezLook", "MultiListSelectionBrush");

         listboxItemWindow->setListboxItem(listbox, winMgr.getWindow("ListboxItem"), CEGUI::UDim(0.0f, 75.0f));
         listbox->addItem(listboxItemWindow);
         listbox->ensureItemIsVisible(listboxItemWindow);
         listbox->setItemSelectState(listboxItemWindow, true);
      }
      catch(Exception &e)
      {
         #if defined( __WIN32__ ) || defined( _WIN32 )
            MessageBox(NULL, e.getMessage().c_str(), "Error initializing the demo", MB_OK | MB_ICONERROR | MB_TASKMODAL);
         #else
            std::cerr << "Error initializing the demo:" << e.getMessage().c_str() << "\n";
         #endif
      }

      return true;
   }

   //----------------------------------------------
    void cleanupSample(void)
   {
   }

   //----------------------------------------------
   bool onListboxItemWindowChildClicked(const CEGUI::EventArgs& e)
   {
      // A child was clicked; forward this event to the listbox so that it can update
      // its "list item selected" flag and properly highlight the list item.
      CEGUI::Listbox* listbox = static_cast<CEGUI::Listbox*>(CEGUI::WindowManager::getSingleton().getWindow("ListWindow/Listbox"));

      // The Listbox contains a series of CEGUI::Window as list items.  The widget that
      // generated the "selection" event can be either a direct child of the window list item
      // or a grand-(potentially add many grands here)-child of that window.

      // Find the immediate parent.
      CEGUI::Window* grandParent;
      CEGUI::Window* parent = static_cast<const CEGUI::WindowEventArgs&>(e).window->getParent();
      while(parent)
      {
         // Check if there is a grand parent
         grandParent = parent->getParent();
         if(!grandParent)
         {
            // This should not have happened so exit this function.
            parent = 0;
            return true;
         }

         // If the grandparent is the Listbox then the parent is the window list item
         if( grandParent->getName().compare( listbox->getName() ) == 0 )
         {
            // Check if the parent window is already selected
            for(CEGUI::ListboxItem* selectedListboxItem = listbox->getFirstSelectedItem();
               selectedListboxItem != 0;
               selectedListboxItem = listbox->getNextSelected(selectedListboxItem))
            {
               if(selectedListboxItem->getText().compare( parent->getText() ) == 0)
               {
                  // Parent is already selected
                  return true;
               }
            }

            // If we reached here then the parent is unselected
            CEGUI::ListboxItem* selectListboxItem = listbox->findItemWithText( parent->getText(), 0);
            listbox->setItemSelectState(selectListboxItem, true);
            return true;
         }

         // Find this parent's parent
         parent = grandParent;
      }
      return true;
   }
};

#endif // _ListboxItemWindow_Demo_h_


And the ListItemWindow.layout that goes with it:

Code: Select all

<?xml version="1.0" encoding="UTF-8"?>

<GUILayout >
    <Window Type="DefaultWindow" Name="Root" >
        <Property Name="InheritsAlpha" Value="False" />
        <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" />
        <Property Name="UnifiedAreaRect" Value="{{0,0},{0,0},{1,0},{1,0}}" />
        <Window Type="TaharezLook/FrameWindow" Name="ListWindow" >
            <Property Name="TitlebarFont" Value="Commonwealth-10" />
            <Property Name="InheritsAlpha" Value="False" />
            <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" />
            <Property Name="TitlebarEnabled" Value="True" />
            <Property Name="UnifiedAreaRect" Value="{{0.001563,0},{0.1375,0},{0.995313,0},{0.416665,0}}" />
            <Window Type="TaharezLook/Listbox" Name="ListWindow/Listbox" >
                <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" />
                <Property Name="UnifiedAreaRect" Value="{{0.051572,0},{0.277293,0},{0.301572,0},{0.854388,0}}" />
            </Window>
            <Window Type="TaharezLook/Combobox" Name="ListWindow/Combobox" >
                <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" />
                <Property Name="UnifiedAreaRect" Value="{{0.351572,0},{0.277293,0},{0.601572,0},{0.854388,0}}" />
                <Property Name="MaxEditTextLength" Value="1073741823" />
            </Window>
            <Window Type="TaharezLook/MultiColumnList" Name="ListWindow/MultiColumnList" >
                <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" />
                <Property Name="UnifiedAreaRect" Value="{{0.651572,0},{0.277293,0},{0.951572,0},{0.854388,0}}" />
            </Window>
        </Window>
        <Window Type="TaharezLook/StaticText" Name="ListboxItem" >
            <Property Name="Alpha" Value="0" />
            <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" />
            <Property Name="UnifiedAreaRect" Value="{{0.03,0},{0.7,0},{0,200},{0,400}}" />
            <Window Type="TaharezLook/StaticImage" Name="ListboxItem/Picture" >
                <Property Name="InheritsAlpha" Value="False" />
                <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" />
                <Property Name="UnifiedAreaRect" Value="{{0.05,0},{0.05,0},{0.33,0},{0.95,0}}" />
            </Window>
            <Window Type="TaharezLook/Checkbox" Name="ListboxItem/Checkbox" >
                <Property Name="Text" Value="Check this box" />
                <Property Name="InheritsAlpha" Value="False" />
                <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" />
                <Property Name="UnifiedAreaRect" Value="{{0.35,0},{0.05,0},{0.95,0},{0,20}}" />
            </Window>
            <Window Type="TaharezLook/Button" Name="ListboxItem/PushButton" >
                <Property Name="Text" Value="Click me!" />
                <Property Name="InheritsAlpha" Value="False" />
                <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" />
                <Property Name="UnifiedAreaRect" Value="{{0.35,0},{0,20},{0.95,0},{0,40}}" />
            </Window>
            <Window Type="TaharezLook/StaticText" Name="ListboxItem/Text" >
                <Property Name="Text" Value="Some text" />
                <Property Name="InheritsAlpha" Value="False" />
                <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" />
                <Property Name="UnifiedAreaRect" Value="{{0.35,0},{0,40},{0.95,0},{0.95,0}}" />
            </Window>
        </Window>
    </Window>
</GUILayout>

Pompei2
Home away from home
Home away from home
Posts: 489
Joined: Tue May 23, 2006 16:31

Postby Pompei2 » Wed Mar 28, 2007 14:48

Great work Rackle !

Will you ever bring it to a state where you want to wiki this ?

Anyways, good job ;)

Rackle
CEGUI Team (Retired)
Posts: 534
Joined: Mon Jan 16, 2006 11:59
Location: Montréal

Postby Rackle » Wed Mar 28, 2007 16:19

I guess that depends on whether the highlight can be made to work. One idea is to relay the highlight action to the listbox item, asking it to highlight/unhilight itself.

However I'm still working on an implementation of Drag and Drop where restrictions can be placed on which DragItem can be dropped in which DropTarget as well as handling complex cases such as when dragging an item from a spellbook and slotting it into a toolbar; you do not want to move the spell from the spellbook. However if you drop the spell into a different slot of the spellbook then in that situation you do want to move it. I've got most of it working. Just need to complete the work.

Then I could turn my attention back to this code snippet, as well as implementing it for a combo box and a multi-column list. Unless someone continues the work for me; anyone can create a wiki, even from this code that I posted.


Return to “Modifications / Integrations / Customisations”

Who is online

Users browsing this forum: No registered users and 11 guests