Logo Search packages:      
Sourcecode: wesnoth-1.7 version File versions  Download package

generator.cpp

/* $Id: generator.cpp 41295 2010-02-20 18:03:19Z mordante $ */
/*
   Copyright (C) 2008 - 2010 by Mark de Wever <koraq@xs4all.nl>
   Part of the Battle for Wesnoth Project http://www.wesnoth.org/

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License version 2
   or at your option any later version.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.

   See the COPYING file for more details.
*/

#define GETTEXT_DOMAIN "wesnoth-lib"

#include "gui/widgets/generator_private.hpp"

#include "gui/widgets/window.hpp"

namespace gui2 {

00023 namespace policy {

/***** ***** ***** ***** Minimum selection ***** ***** ***** *****/

00027 namespace minimum_selection {

00029 void tone::set_item_shown(const unsigned index, const bool show)
{
      if(show && get_selected_item_count() == 0) {
            do_select_item(index);
      } else if(!show && is_selected(index)) {
            do_deselect_item(index);

            for(unsigned i = index + 1; i < get_item_count(); ++i) {
                  if(get_item_shown(i)) {
                        do_select_item(i);
                        break;
                  }
            }
      }
}

00045 void tone::create_item(const unsigned index)
{
      if(get_selected_item_count() == 0) {
            do_select_item(index);
      }
}

00052 bool tone::deselect_item(const unsigned index)
{
      if(get_selected_item_count() > 1) {
            do_deselect_item(index);
            return true;
      }
      return false;
}

00061 void tone::delete_item(const unsigned index)
{
      /** @todo do_select_item needs to test for shown flag. */

      if(is_selected(index)) {
            do_deselect_item(index);

            if(get_selected_item_count() == 0) {

                  // Are there items left?
                  const unsigned item_count = get_item_count();
                  if(item_count > 1) {
                        // Is the last item deselected?
                        if(index == item_count - 1) {
                              // Select the second last.
                              do_select_item(index - 1);
                        } else {
                              // Select the next item.
                              do_select_item(index + 1);
                        }
                  }
            }
      }
}

00086 void tnone::set_item_shown(const unsigned index, const bool show)
{
      if(!show && is_selected(index)) {
            do_deselect_item(index);
      }
}

} // namespace minimum_selection

/***** ***** ***** ***** Placement ***** ***** ***** *****/

00097 namespace placement {

thorizontal_list::thorizontal_list()
      : placed_(false)
{
}

00104 void thorizontal_list::create_item(const unsigned /*index*/)
{
      if(!placed_) {
            return;
      }

      /** @todo implement. */
      assert(false);
}

00114 tpoint thorizontal_list::calculate_best_size() const
{
      // The best size is the sum of the widths and the greatest height.
      tpoint result(0, 0);
      for(size_t i = 0; i < get_item_count(); ++i) {

            const tgrid& grid = item(i);
            if(grid.get_visible() == twidget::INVISIBLE || !get_item_shown(i)) {
                  continue;
            }

            const tpoint best_size = grid.get_best_size();

            result.x += best_size.x;

            if(best_size.y > result.y) {
                  result.y = best_size.y;
            }
      }

      return result;
}

00137 void thorizontal_list::place(const tpoint& origin, const tpoint& size)
{
      /*
       * - Set every item to it's best size.
       * - The origin gets increased with the width of the last item.
       * - No item should be higher as the size.
       * - In the end the origin should be the sum or the origin and the wanted
       *   width.
       */

      tpoint current_origin = origin;
      for(size_t i = 0; i < get_item_count(); ++i) {

            tgrid& grid = item(i);
            if(grid.get_visible() == twidget::INVISIBLE || !get_item_shown(i)) {
                  continue;
            }

            tpoint best_size = grid.get_best_size();
            assert(best_size.y <= size.y);
            // FIXME should we look at grow factors???
            best_size.y = size.y;

            grid.place(current_origin, best_size);

            current_origin.x += best_size.x;
      }

      assert(current_origin.x == origin.x + size.x);
}

00168 void thorizontal_list::set_origin(const tpoint& origin)
{
      tpoint current_origin = origin;
      for(size_t i = 0; i < get_item_count(); ++i) {

            tgrid& grid = item(i);
            if(grid.get_visible() == twidget::INVISIBLE || !get_item_shown(i)) {
                  continue;
            }

            grid.set_origin(current_origin);
            current_origin.x += grid.get_width();
      }
}

00183 void thorizontal_list::set_visible_area(const SDL_Rect& area)
{
      /*
       * Note for most implementations this function could work only for the
       * tindependant class it probably fails. Evalute to make a generic
       * function in the tgenerator template class and call it from the wanted
       * placement functions.
       */
      for(size_t i = 0; i < get_item_count(); ++i) {

            tgrid& grid = item(i);
            grid.set_visible_area(area);
      }
}

00198 twidget* thorizontal_list::find_at(
            const tpoint& coordinate, const bool must_be_active)
{
      twindow* window = get_window();
      assert(window);

      for(size_t i = 0; i < get_item_count(); ++i) {

            tgrid& grid = item(i);
            if(grid.get_visible() == twidget::INVISIBLE || !get_item_shown(i)) {
                  continue;
            }

            twidget* widget =
                        grid.find_at(coordinate, must_be_active);

            if(widget) {
                  return widget;
            }
      }
      return NULL;
}

00221 const twidget* thorizontal_list::find_at(const tpoint& coordinate,
            const bool must_be_active) const
{
      const twindow* window = get_window();
      assert(window);

      for(size_t i = 0; i < get_item_count(); ++i) {

            const tgrid& grid = item(i);
            if(grid.get_visible() == twidget::INVISIBLE || !get_item_shown(i)) {
                  continue;
            }

            const twidget* widget =
                        grid.find_at(coordinate, must_be_active);

            if(widget) {
                  return widget;
            }
      }
      return NULL;
}

00244 void thorizontal_list::handle_key_left_arrow(
            SDLMod /*modifier*/, bool& handled)
{
      if(get_selected_item_count() == 0) {
            return;
      }

      // NOTE maybe this should only work if we can select only one item...
      handled = true;

      for(int i = get_selected_item() - 1; i >= 0; --i) {

            // NOTE we check the first widget to be active since grids have no
            // active flag. This method might not be entirely reliable.
            tcontrol* control = dynamic_cast<tcontrol*>(item(i).widget(0, 0));
            if(control && control->get_active()) {
                  select_item(i);
                  return;
            }
      }
}

00266 void thorizontal_list::handle_key_right_arrow(
            SDLMod /*modifier*/, bool& handled)
{
      if(get_selected_item_count() == 0) {
            return;
      }

      // NOTE maybe this should only work if we can select only one item...
      handled = true;

      for(size_t i = get_selected_item() + 1; i < get_item_count(); ++i) {

            if(item(i).get_visible() == twidget::INVISIBLE
                        || !get_item_shown(i)) {

                  continue;
            }

            // NOTE we check the first widget to be active since grids have no
            // active flag. This method might not be entirely reliable.
            tcontrol* control = dynamic_cast<tcontrol*>(item(i).widget(0, 0));
            if(control && control->get_active()) {
                  select_item(i);
                  return;
            }
      }
}

tvertical_list::tvertical_list()
      : placed_(false)
{
}

00299 void tvertical_list::create_item(const unsigned /*index*/)
{
      if(!placed_) {
            return;
      }

      /** @todo implement. */
      assert(false);
}

00309 tpoint tvertical_list::calculate_best_size() const
{
      // The best size is the sum of the heights and the greatest width.
      tpoint result(0, 0);
      for(size_t i = 0; i < get_item_count(); ++i) {

            const tgrid& grid = item(i);
            if(grid.get_visible() == twidget::INVISIBLE || !get_item_shown(i)) {
                  continue;
            }

            const tpoint best_size = grid.get_best_size();

            if(best_size.x > result.x) {
                  result.x = best_size.x;
            }

            result.y += best_size.y;
      }

      return result;
}

00332 void tvertical_list::place(const tpoint& origin, const tpoint& size)
{
      /*
       * - Set every item to it's best size.
       * - The origin gets increased with the height of the last item.
       * - No item should be wider as the size.
       * - In the end the origin should be the sum or the origin and the wanted
       *   height.
       */

      tpoint current_origin = origin;
      for(size_t i = 0; i < get_item_count(); ++i) {

            tgrid& grid = item(i);
            if(grid.get_visible() == twidget::INVISIBLE || !get_item_shown(i)) {
                  continue;
            }

            tpoint best_size = grid.get_best_size();
            assert(best_size.x <= size.x);
            // FIXME should we look at grow factors???
            best_size.x = size.x;

            grid.place(current_origin, best_size);

            current_origin.y += best_size.y;
      }

      assert(current_origin.y == origin.y + size.y);
}

00363 void tvertical_list::set_origin(const tpoint& origin)
{
      tpoint current_origin = origin;
      for(size_t i = 0; i < get_item_count(); ++i) {

            tgrid& grid = item(i);
            if(grid.get_visible() == twidget::INVISIBLE || !get_item_shown(i)) {
                  continue;
            }

            grid.set_origin(current_origin);
            current_origin.y += grid.get_height();
      }
}

00378 void tvertical_list::set_visible_area(const SDL_Rect& area)
{
      /*
       * Note for most implementations this function could work only for the
       * tindependant class it probably fails. Evalute to make a generic
       * function in the tgenerator template class and call it from the wanted
       * placement functions.
       */
      for(size_t i = 0; i < get_item_count(); ++i) {

            tgrid& grid = item(i);
            grid.set_visible_area(area);
      }
}

00393 twidget* tvertical_list::find_at(
            const tpoint& coordinate, const bool must_be_active)
{
      twindow* window = get_window();
      assert(window);

      for(size_t i = 0; i < get_item_count(); ++i) {

            tgrid& grid = item(i);
            if(grid.get_visible() == twidget::INVISIBLE || !get_item_shown(i)) {
                  continue;
            }


            twidget* widget =
                        grid.find_at(coordinate, must_be_active);

            if(widget) {
                  return widget;
            }
      }
      return NULL;
}

00417 const twidget* tvertical_list::find_at(const tpoint& coordinate,
            const bool must_be_active) const
{
      const twindow* window = get_window();
      assert(window);

      for(size_t i = 0; i < get_item_count(); ++i) {

            const tgrid& grid = item(i);
            if(grid.get_visible() == twidget::INVISIBLE || !get_item_shown(i)) {
                  continue;
            }

            const twidget* widget =
                        grid.find_at(coordinate, must_be_active);

            if(widget) {
                  return widget;
            }
      }
      return NULL;
}

00440 void tvertical_list::handle_key_up_arrow(SDLMod /*modifier*/, bool& handled)
{
      if(get_selected_item_count() == 0) {
            return;
      }

      // NOTE maybe this should only work if we can select only one item...
      handled = true;

      for(int i = get_selected_item() - 1; i >= 0; --i) {

            // NOTE we check the first widget to be active since grids have no
            // active flag. This method might not be entirely reliable.
            tcontrol* control = dynamic_cast<tcontrol*>(item(i).widget(0, 0));
            if(control && control->get_active()) {
                  select_item(i);
                  return;
            }
      }
}

00461 void tvertical_list::handle_key_down_arrow(SDLMod /*modifier*/, bool& handled)
{
      if(get_selected_item_count() == 0) {
            return;
      }

      // NOTE maybe this should only work if we can select only one item...
      handled = true;

      for(size_t i = get_selected_item() + 1; i < get_item_count(); ++i) {

            if(item(i).get_visible() == twidget::INVISIBLE
                              || !get_item_shown(i)) {

                  continue;
            }

            // NOTE we check the first widget to be active since grids have no
            // active flag. This method might not be entirely reliable.
            tcontrol* control = dynamic_cast<tcontrol*>(item(i).widget(0, 0));
            if(control && control->get_active()) {
                  select_item(i);
                  return;
            }
      }
}

00488 void tindependant::request_reduce_width(const unsigned maximum_width)
{
      for(size_t i = 0; i < get_item_count(); ++i) {

            tgrid& grid = item(i);
            grid.request_reduce_width(maximum_width);
      }
}

00497 void tindependant::request_reduce_height(const unsigned maximum_height)
{
      for(size_t i = 0; i < get_item_count(); ++i) {

            tgrid& grid = item(i);
            grid.request_reduce_height(maximum_height);
      }
}

00506 tpoint tindependant::calculate_best_size() const
{
      /*
       * The best size is the combination of the greatest width and greatest
       * height.
       */
      tpoint result(0, 0);
      for(size_t i = 0; i < get_item_count(); ++i) {

            const tgrid& grid = item(i);

            const tpoint best_size = grid.get_best_size();

            if(best_size.x > result.x) {
                  result.x = best_size.x;
            }

            if(best_size.y > result.y) {
                  result.y = best_size.y;
            }
      }

      return result;
}

00531 void tindependant::place(const tpoint& origin, const tpoint& size)
{
      for(size_t i = 0; i < get_item_count(); ++i) {

            tgrid& grid = item(i);
            grid.place(origin, size);
      }
}

00540 void tindependant::set_origin(const tpoint& origin)
{
      /*
       * Set the origin for every item.
       *
       * @todo evaluate whether setting it only for the visible item is better
       * and what the consequences are.
       */
      for(size_t i = 0; i < get_item_count(); ++i) {

            tgrid& grid = item(i);
            grid.set_origin(origin);
      }
}

00555 twidget* tindependant::find_at(const tpoint& coordinate
            , const bool must_be_active)
{
      const twindow* window = get_window();
      assert(window);

      const int selected_item = get_selected_item();
      if(selected_item < 0) {
            return NULL;
      }

      tgrid& grid = item(selected_item);
      return grid.find_at(coordinate, must_be_active);
}

00570 const twidget* tindependant::find_at(const tpoint& coordinate
            , const bool must_be_active) const
{
      const twindow* window = get_window();
      assert(window);

      const int selected_item = get_selected_item();
      if(selected_item < 0) {
            return NULL;
      }

      const tgrid& grid = item(selected_item);
      return grid.find_at(coordinate, must_be_active);
}

00585 twidget* tindependant::find(
            const std::string& id, const bool must_be_active)
{
      for(size_t i = 0; i < get_item_count(); ++i) {
            if(is_selected(i)) {
                  if(twidget* widget = item(i).find(id, must_be_active)) {
                        return widget;
                  }
            }
      }
      return NULL;
}

00598 const twidget* tindependant::find(
            const std::string& id, const bool must_be_active) const
{
      for(size_t i = 0; i < get_item_count(); ++i) {
            if(is_selected(i)) {
                  if(const twidget* widget =
                              item(i).find(id, must_be_active)) {

                        return widget;
                  }
            }
      }
      return NULL;
}

00613 void tindependant::set_visible_area(const SDL_Rect& area)
{
      /*
       * Set the visible area for every item.
       *
       * @todo evaluate whether setting it only for the visible item is better
       * and what the consequences are.
       */
      for(size_t i = 0; i < get_item_count(); ++i) {

            tgrid& grid = item(i);
            grid.set_visible_area(area);
      }
}

} // namespace placement

/***** ***** ***** ***** Select action ***** ***** ***** *****/

00632 namespace select_action {

void tselect::select(tgrid& grid, const bool select)
{
      tselectable_* selectable =
                  dynamic_cast<tselectable_*>(grid.widget(0, 0));
      assert(selectable);

      selectable->set_value(select);
}

00643 void tselect::init(tgrid* grid
            , const std::map<std::string /* widget id */, string_map>& data
            , void (*callback)(twidget*))
{
      for(unsigned row = 0; row < grid->get_rows(); ++row) {
            for(unsigned col = 0; col < grid->get_cols(); ++col) {
                  twidget* widget = grid->widget(row, col);
                  assert(widget);

                  tgrid* child_grid = dynamic_cast<tgrid*>(widget);
                  ttoggle_button* btn = dynamic_cast<ttoggle_button*>(widget);
                  ttoggle_panel* panel = dynamic_cast<ttoggle_panel*>(widget);

                  if(btn) {
                        btn->set_callback_state_change(callback);
                        std::map<std::string, string_map>::const_iterator itor =
                                    data.find(btn->id());

                        if(itor == data.end()) {
                              itor = data.find("");
                        }
                        if(itor != data.end()) {
                              btn->set_members(itor->second);
                        }
                  } else if(panel) {
                        panel->set_callback_state_change(callback);
                        panel->set_child_members(data);
                  } else if(child_grid) {
                        init(child_grid, data, callback);
                  } else {
                        ERROR_LOG("Widget type '"
                                    << typeid(*widget).name() << "'.");
                  }
            }
      }
}

00680 void tshow::init(tgrid* grid
            , const std::map<std::string /* widget id */, string_map>& data
            , void (*callback)(twidget*))
{
      assert(!callback);

      typedef std::pair<std::string, string_map> hack;
      foreach(const hack& item, data) {
            if(item.first.empty()) {
                  for(unsigned row = 0; row < grid->get_rows(); ++row) {
                        for(unsigned col = 0; col < grid->get_cols(); ++col) {
                              if(tcontrol* control =
                                          dynamic_cast<tcontrol*>(grid->widget(row, col))) {

                                    control->set_members(item.second);
                              }
                        }
                  }
            } else {
                  tcontrol* control = dynamic_cast<
                              tcontrol*>(grid->find(item.first, false));
                  if(control) {
                        control->set_members(item.second);
                  }
            }
      }
}

} // namespace select_action

} // namespace policy

/***** ***** ***** ***** Helper macros ***** ***** ***** *****/

#ifdef GENERATE_PLACEMENT
char compile_assert[0];
#else
#define GENERATE_PLACEMENT                                 \
switch(placement) {                                        \
      case tgenerator_::horizontal_list :                    \
            result = new tgenerator                            \
                        < minimum                                  \
                        , maximum                                  \
                        , policy::placement::thorizontal_list      \
                        , select                                   \
                        >;                                         \
            break;                                             \
      case tgenerator_::vertical_list :                      \
            result = new tgenerator                            \
                        < minimum                                  \
                        , maximum                                  \
                        , policy::placement::tvertical_list        \
                        , select                                   \
                        >;                                         \
            break;                                             \
      case tgenerator_::grid :                               \
            result = new tgenerator                            \
                        < minimum                                  \
                        , maximum                                  \
                        , policy::placement::tmatrix               \
                        , select                                   \
                        >;                                         \
            break;                                             \
      case tgenerator_::independant :                        \
            result = new tgenerator                            \
                        < minimum                                  \
                        , maximum                                  \
                        , policy::placement::tindependant          \
                        , select                                   \
                        >;                                         \
            break;                                             \
      default:                                               \
            assert(false);                                     \
}
#endif

#ifdef GENERATE_SELECT
char compile_assert[0];
#else
#define GENERATE_SELECT                                    \
if(select) {                                               \
      typedef policy::select_action::tselect select;         \
      GENERATE_PLACEMENT                                     \
} else {                                                   \
      typedef policy::select_action::tshow select;           \
      GENERATE_PLACEMENT                                     \
}
#endif

#ifdef GENERATE_MAXIMUM
char compile_assert[0];
#else
#define GENERATE_MAXIMUM                                   \
if(has_maximum) {                                          \
      typedef policy::maximum_selection::tone maximum;       \
      GENERATE_SELECT                                        \
} else {                                                   \
      typedef policy::maximum_selection::tinfinite maximum;  \
      GENERATE_SELECT                                        \
}
#endif

#ifdef GENERATE_BODY
char compile_assert[0];
#else
#define GENERATE_BODY                                     \
if(has_minimum) {                                         \
      typedef policy::minimum_selection::tone minimum;      \
      GENERATE_MAXIMUM                                      \
} else {                                                  \
      typedef policy::minimum_selection::tnone minimum;     \
      GENERATE_MAXIMUM                                      \
}
#endif

00795 tgenerator_* tgenerator_::build(
            const bool has_minimum, const bool has_maximum,
            const tplacement placement, const bool select)
{
      tgenerator_* result = NULL;
      GENERATE_BODY;
      return result;
}

/***** ***** ***** ***** Test code ***** ***** ***** *****/
#if 0
namespace {

void pointer_test()
{

      tgenerator_ *a = tgenerator_::build(
                  true, true, tgenerator_::horizontal_list, true);

      tgenerator_ *b = tgenerator_::build(
                  true, false, tgenerator_::horizontal_list, true);

      tgenerator_ *c = tgenerator_::build(
                  false, true, tgenerator_::horizontal_list, true);

      tgenerator_ *d = tgenerator_::build(
                  false, false, tgenerator_::horizontal_list, true);

      a->clear();
      b->clear();
      c->clear();
      d->clear();

      delete a;
      delete b;
      delete c;
      delete d;
}

void direct_test()
{
      tgenerator
            < policy::minimum_selection::tone
            , policy::maximum_selection::tone
            , policy::placement::tvertical_list
            , policy::select_action::tselect
            > a;

      tgenerator
            < policy::minimum_selection::tone
            , policy::maximum_selection::tinfinite
            , policy::placement::tvertical_list
            , policy::select_action::tselect
            > b;

      tgenerator
            < policy::minimum_selection::tnone
            , policy::maximum_selection::tone
            , policy::placement::tvertical_list
            , policy::select_action::tselect
            > c;

      tgenerator
            < policy::minimum_selection::tnone
            , policy::maximum_selection::tinfinite
            , policy::placement::tvertical_list
            , policy::select_action::tselect
            > d;

      a.clear();
      b.clear();
      c.clear();
      d.clear();

}

} // namespace
#endif

} // namespace gui2


Generated by  Doxygen 1.6.0   Back to index