Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "textlist.h"
Toshihiro Shimizu 890ddd
#include "tw/colors.h"
Toshihiro Shimizu 890ddd
#include "tw/event.h"
Toshihiro Shimizu 890ddd
#include "tw/scrollbar.h"
Toshihiro Shimizu 890ddd
#include "tw/keycodes.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <vector></vector>
Toshihiro Shimizu 890ddd
#include <map></map>
Toshihiro Shimizu 890ddd
#include <string></string>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace std;
Toshihiro Shimizu 890ddd
using namespace TwConsts;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Shinya Kitaoka 120a6e
const int rowHeight = 20;  // 15
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class TTextList::Data {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  Data(TWidget *w)
Shinya Kitaoka 120a6e
      : m_w(w)
Shinya Kitaoka 120a6e
      , m_selAction(0)
Shinya Kitaoka 120a6e
      , m_dblClickAction(0)
Shinya Kitaoka 120a6e
      , m_scrollbar(new TScrollbar(w))
Shinya Kitaoka 120a6e
      , m_yoffset(0) {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ~Data() {
Shinya Kitaoka 120a6e
    if (m_selAction) delete m_selAction;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_dblClickAction) delete m_dblClickAction;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    std::map<string, *="" ttextlistitem="">::iterator it = m_items.begin();</string,>
Shinya Kitaoka 120a6e
    for (; it != m_items.end(); ++it) delete it->second;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int posToItem(const TPoint &p);
Shinya Kitaoka 120a6e
  void updateScrollBarStatus() {
Shinya Kitaoka 120a6e
    if (!m_scrollbar) return;
Shinya Kitaoka 120a6e
    unsigned int ly = m_w->getLy();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if ((m_items.size() * rowHeight) > ly) {
Shinya Kitaoka 120a6e
      m_scrollbar->setValue(m_yoffset, 0, (m_items.size() + 1) * rowHeight - ly,
Shinya Kitaoka 120a6e
                            ly);
Shinya Kitaoka 120a6e
      m_scrollbar->show();  // m_scrollbar->setValue(m_yoffset,0, yrange-ly,
Shinya Kitaoka 120a6e
                            // ly);
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      m_yoffset = 0;
Shinya Kitaoka 120a6e
      m_scrollbar->hide();  // m_scrollbar->setValue(0,0, 0, 0);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    m_scrollbar->invalidate();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TWidget *m_w;
Shinya Kitaoka 120a6e
  std::map<string, *="" ttextlistitem=""> m_items;</string,>
Shinya Kitaoka 120a6e
  vector<string> m_selectedItems;</string>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TGenericTextListAction *m_selAction;
Shinya Kitaoka 120a6e
  TGenericTextListAction *m_dblClickAction;
Shinya Kitaoka 120a6e
  TScrollbar *m_scrollbar;
Shinya Kitaoka 120a6e
  int m_yoffset;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TTextList::Data::posToItem(const TPoint &p) {
Shinya Kitaoka 120a6e
  /*  TDimension d = getSize();
Shinya Kitaoka 120a6e
int i = getItemCount()-1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
10 +
Shinya Kitaoka 120a6e
for(int y=10; y<d.ly &&="" i="">=0; y+=rowHeight, --i)</d.ly>
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int y    = m_w->getSize().ly - p.y + m_yoffset;
Shinya Kitaoka 120a6e
  int item = y / rowHeight;
Shinya Kitaoka 120a6e
  return item;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TTextListItem::TTextListItem(const string &id, const string &caption)
Shinya Kitaoka 120a6e
    : m_id(id), m_caption(caption) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TTextList::TTextList(TWidget *parent, string name)
Shinya Kitaoka 120a6e
    : TWidget(parent, name), m_data(0) {
Shinya Kitaoka 120a6e
  m_data = new Data(this);
Shinya Kitaoka 120a6e
  m_data->m_scrollbar->setAction(
Shinya Kitaoka 120a6e
      new TScrollbarAction<ttextlist>(this, &TTextList::scrollTo));</ttextlist>
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TTextList::~TTextList() { delete m_data; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TTextList::addItem(TTextListItem *item) {
Shinya Kitaoka 120a6e
  std::map<string, *="" ttextlistitem="">::iterator it =</string,>
Shinya Kitaoka 120a6e
      m_data->m_items.find(item->getId());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (it == m_data->m_items.end()) {
Shinya Kitaoka 120a6e
    m_data->m_items.insert(make_pair(item->getId(), item));
Shinya Kitaoka 120a6e
    m_data->updateScrollBarStatus();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TTextList::removeItem(const string &itemId) {
Shinya Kitaoka 120a6e
  std::map<string, *="" ttextlistitem="">::iterator it = m_data->m_items.find(itemId);</string,>
Shinya Kitaoka 120a6e
  if (it != m_data->m_items.end()) {
Shinya Kitaoka 120a6e
    m_data->m_items.erase(it);
Shinya Kitaoka 120a6e
    m_data->updateScrollBarStatus();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TTextList::clearAll() {
Shinya Kitaoka 120a6e
  m_data->m_items.clear();
Shinya Kitaoka 120a6e
  m_data->m_selectedItems.clear();
Shinya Kitaoka 120a6e
  invalidate();
Shinya Kitaoka 120a6e
  m_data->updateScrollBarStatus();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TTextList::getItemCount() const { return m_data->m_items.size(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TTextListItem *TTextList::getItem(int i) const {
Shinya Kitaoka 120a6e
  if (i >= 0 && i < (int)m_data->m_items.size()) {
Shinya Kitaoka 120a6e
    std::map<string, *="" ttextlistitem="">::iterator it = m_data->m_items.begin();</string,>
Shinya Kitaoka 120a6e
    advance(it, i);
Shinya Kitaoka 120a6e
    return it->second;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TTextList::itemToIndex(const string &itemId) {
Shinya Kitaoka 120a6e
  std::map<string, *="" ttextlistitem="">::iterator it = m_data->m_items.find(itemId);</string,>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (it == m_data->m_items.end())
Shinya Kitaoka 120a6e
    return -1;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return distance(m_data->m_items.begin(), it);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TTextList::getSelectedItemCount() const {
Shinya Kitaoka 120a6e
  return m_data->m_selectedItems.size();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TTextListItem *TTextList::getSelectedItem(int i) const {
Shinya Kitaoka 120a6e
  if (i < 0 || (int)m_data->m_selectedItems.size() <= i) return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  string itemId = m_data->m_selectedItems[i];
Shinya Kitaoka 120a6e
  std::map<string, *="" ttextlistitem="">::iterator it = m_data->m_items.find(itemId);</string,>
Shinya Kitaoka 120a6e
  if (it != m_data->m_items.end())
Shinya Kitaoka 120a6e
    return it->second;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
string TTextList::getSelectedItemId(int i) const {
Shinya Kitaoka 120a6e
  if ((int)m_data->m_selectedItems.size() <= i) return "";
Shinya Kitaoka 120a6e
  assert(i >= 0 && i < (int)m_data->m_selectedItems.size());
Shinya Kitaoka 120a6e
  return m_data->m_selectedItems[i];
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TTextList::select(int i, bool on) {
Shinya Kitaoka 120a6e
  assert(i >= 0 && i < (int)m_data->m_items.size());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::map<string, *="" ttextlistitem="">::iterator it = m_data->m_items.begin();</string,>
Shinya Kitaoka 120a6e
  advance(it, i);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  string id = it->first;
Shinya Kitaoka 120a6e
  vector<string>::iterator it2 =</string>
Shinya Kitaoka 120a6e
      find(m_data->m_selectedItems.begin(), m_data->m_selectedItems.end(), id);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (on) {
Shinya Kitaoka 120a6e
    if (it2 == m_data->m_selectedItems.end())
Shinya Kitaoka 120a6e
      m_data->m_selectedItems.push_back(id);
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    if (it2 != m_data->m_selectedItems.end())
Shinya Kitaoka 120a6e
      m_data->m_selectedItems.erase(it2);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_data->m_selAction) m_data->m_selAction->sendCommand(i);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TTextList::select(const string &itemId, bool on) {
Shinya Kitaoka 120a6e
  std::map<string, *="" ttextlistitem="">::iterator it = m_data->m_items.find(itemId);</string,>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (it != m_data->m_items.end()) {
Shinya Kitaoka 120a6e
    int i = distance(m_data->m_items.begin(), it);
Shinya Kitaoka 120a6e
    select(i, on);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TTextList::unselectAll() {
Shinya Kitaoka 120a6e
  m_data->m_selectedItems.clear();
Shinya Kitaoka 120a6e
  invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TTextList::isSelected(int i) const {
Shinya Kitaoka 120a6e
  assert(i >= 0 && i < (int)m_data->m_items.size());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::map<string, *="" ttextlistitem="">::iterator it = m_data->m_items.begin();</string,>
Shinya Kitaoka 120a6e
  advance(it, i);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  string id = it->first;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  vector<string>::iterator it2 =</string>
Shinya Kitaoka 120a6e
      find(m_data->m_selectedItems.begin(), m_data->m_selectedItems.end(), id);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return it2 != m_data->m_selectedItems.end();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TTextList::isSelected(const string &item) const {
Shinya Kitaoka 120a6e
  assert(false);
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TTextList::scrollTo(int y) {
Shinya Kitaoka 120a6e
  y = (y / rowHeight) * rowHeight;
Shinya Kitaoka 120a6e
  if (m_data->m_yoffset == y) return;
Shinya Kitaoka 120a6e
  m_data->m_yoffset = y;
Shinya Kitaoka 120a6e
  m_data->updateScrollBarStatus();
Shinya Kitaoka 120a6e
  invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TTextList::draw() {
Shinya Kitaoka 120a6e
  drawRect(TRect(TPoint(0, 0), getSize()));
Shinya Kitaoka 120a6e
  TDimension d = getSize();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int y = d.ly - 1 - rowHeight;
Shinya Kitaoka 120a6e
  for (int i = m_data->m_yoffset / rowHeight; i < getItemCount() && y >= 0;
Shinya Kitaoka 120a6e
       ++i, y -= rowHeight) {
Shinya Kitaoka 120a6e
    if (isSelected(i)) {
Shinya Kitaoka 120a6e
      setColor(Blue, 2);
Shinya Kitaoka 120a6e
      fillRect(2, y - 2, getSize().lx - 1 - 2, y + rowHeight - 1 - 2);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    setColor(Black);
Shinya Kitaoka 120a6e
    drawText(TPoint(10, y), getItem(i)->getCaption());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TTextList::setSelAction(TGenericTextListAction *action) {
Shinya Kitaoka 120a6e
  if (m_data->m_selAction) delete m_data->m_selAction;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_data->m_selAction = action;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TTextList::setDblClickAction(TGenericTextListAction *action) {
Shinya Kitaoka 120a6e
  if (m_data->m_dblClickAction) delete m_data->m_dblClickAction;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_data->m_dblClickAction = action;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TTextList::configureNotify(const TDimension &d) {
Shinya Kitaoka 120a6e
  m_data->m_scrollbar->setGeometry(d.lx - 20, 1, d.lx - 2, d.ly - 2);
Shinya Kitaoka 120a6e
  m_data->updateScrollBarStatus();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TTextList::leftButtonDown(const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  int i = m_data->posToItem(e.m_pos);
Shinya Kitaoka 120a6e
  if (i >= 0 && i < (int)m_data->m_items.size()) {
Shinya Kitaoka 120a6e
    if (!e.isShiftPressed()) unselectAll();
Shinya Kitaoka 120a6e
    select(i, !isSelected(i));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TTextList::leftButtonDoubleClick(const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  int i = m_data->posToItem(e.m_pos);
Shinya Kitaoka 120a6e
  if (i >= 0 && i < (int)m_data->m_items.size()) {
Shinya Kitaoka 120a6e
    if (m_data->m_dblClickAction) m_data->m_dblClickAction->sendCommand(i);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TTextList::keyDown(int key, unsigned long mod, const TPoint &pos) {
Shinya Kitaoka 120a6e
  if ((key == TK_UpArrow) || (key == TK_DownArrow)) {
Shinya Kitaoka 120a6e
    int lastSelected = -1;
Shinya Kitaoka 120a6e
    for (int i                        = 0; i < getItemCount(); ++i)
Shinya Kitaoka 120a6e
      if (isSelected(i)) lastSelected = i;
Shinya Kitaoka 120a6e
    if (lastSelected == -1) return;
Shinya Kitaoka 120a6e
    int newSelected = (key == TK_UpArrow) ? lastSelected - 1 : lastSelected + 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (newSelected >= 0 && newSelected < (int)m_data->m_items.size()) {
Shinya Kitaoka 120a6e
      //   if (!e.isShiftPressed())
Shinya Kitaoka 120a6e
      unselectAll();
Shinya Kitaoka 120a6e
      select(newSelected, !isSelected(newSelected));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    TWidget::keyDown(key, mod, pos);
Toshihiro Shimizu 890ddd
}