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

generator.cpp

/* $Id: generator.cpp 46186 2010-09-01 21:12:38Z silene $ */
/*
   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 as published by
   the Free Software Foundation; either version 2 of the License, 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 {

00024 namespace policy {

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

00028 namespace minimum_selection {

00030 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;
                  }
            }
      }
}

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

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

00062 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);
                        }
                  }
            }
      }
}

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

} // namespace minimum_selection

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

00098 namespace placement {

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

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

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

00115 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;
}

00138 void thorizontal_list::place(const tpoint& origin, const tpoint& size)
{
      /*
       * - Set every item to its 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);
}

00169 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();
      }
}

00184 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);
      }
}

00199 twidget* thorizontal_list::find_at(
            const tpoint& coordinate, const bool must_be_active)
{
      assert(get_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
{
      assert(get_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;
}

00243 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;
            }
      }
}

00265 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)
{
}

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

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

00308 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;
}

00331 void tvertical_list::place(const tpoint& origin, const tpoint& size)
{
      /*
       * - Set every item to its 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);
}

00362 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();
      }
}

00377 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);
      }
}

00392 twidget* tvertical_list::find_at(
            const tpoint& coordinate, const bool must_be_active)
{
      assert(get_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;
}

00415 const twidget* tvertical_list::find_at(const tpoint& coordinate,
            const bool must_be_active) const
{
      assert(get_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;
}

00437 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;
            }
      }
}

00458 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;
            }
      }
}

00485 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);
      }
}

00494 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);
      }
}

00503 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;
}

00528 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);
      }
}

00537 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);
      }
}

00552 twidget* tindependant::find_at(const tpoint& coordinate
            , const bool must_be_active)
{
      assert(get_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);
}

00566 const twidget* tindependant::find_at(const tpoint& coordinate
            , const bool must_be_active) const
{
      assert(get_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);
}

00580 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;
}

00593 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;
}

00608 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 ***** ***** ***** *****/

00627 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);
}

00638 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 {
                        VALIDATE(false, "Only toggle buttons and panels are allowed as the cells of a list definition.");
                  }
            }
      }
}

00674 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

00789 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