aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gui/ListWidget.cpp129
-rw-r--r--gui/ListWidget.h3
-rw-r--r--gui/dialog.cpp23
-rw-r--r--gui/util.cpp8
-rw-r--r--gui/util.h1
-rw-r--r--gui/widget.cpp3
-rw-r--r--gui/widget.h6
7 files changed, 164 insertions, 9 deletions
diff --git a/gui/ListWidget.cpp b/gui/ListWidget.cpp
index f435663bc5..9781ed4912 100644
--- a/gui/ListWidget.cpp
+++ b/gui/ListWidget.cpp
@@ -27,8 +27,6 @@
/*
* TODO:
- * - Implement scrolling using arrow keys, pageup/pagedown, home/end keys etc.
- * - Implement editing of the selected string in a generic fashion
*/
@@ -39,7 +37,7 @@
ListWidget::ListWidget(Dialog *boss, int x, int y, int w, int h)
: Widget(boss, x, y, w - kScrollBarWidth, h)
{
- _flags = WIDGET_ENABLED | WIDGET_CLEARBG;
+ _flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS | WIDGET_WANT_TICKLE;
_type = kListWidget;
_numberingMode = kListNumberingOne;
_entriesPerPage = (_h - 4) / LINE_HEIGHT;
@@ -48,6 +46,11 @@ ListWidget::ListWidget(Dialog *boss, int x, int y, int w, int h)
_scrollBar = new ScrollBarWidget(boss, _x + _w, _y, kScrollBarWidth, _h);
_scrollBar->setTarget(this);
+ // FIXME: This flag should come from widget definition
+ _editable = true;
+
+ _editMode = false;
+
// FIXME - fill in dummy data for now
_list.push_back("A simple game?");
_list.push_back("This space for rent!");
@@ -81,14 +84,114 @@ ListWidget::~ListWidget()
void ListWidget::handleMouseDown(int x, int y, int button)
{
+ int oldSelectedItem = _selectedItem;
+
if (_flags & WIDGET_ENABLED) {
_selectedItem = (y - 2) / LINE_HEIGHT + _currentPos;
+
+ if (_editMode && oldSelectedItem != _selectedItem) {
+ // loose caret
+ _list[_selectedItem].deleteLastChar();
+ _editMode = false;
+ }
draw();
}
}
void ListWidget::handleKeyDown(char key, int modifiers)
{
+ bool dirty = false;
+ int oldSelectedItem = _selectedItem;
+
+ if (_editMode) {
+
+ // get rid of caret
+ _list[_selectedItem].deleteLastChar();
+
+ if (key == '\n' || key == '\r') {
+ // enter, exit editmode
+ _editMode = false;
+ dirty = true;
+ }
+ else if (_editMode && key == 8) { // backspace
+ _list[_selectedItem].deleteLastChar();
+ dirty = true;
+ } else if (_editMode &&
+ // filter keystrokes
+ ( ( key >= 'a' && key <= 'z' )
+ || ( key >= 'A' && key <= 'Z' )
+ || ( key >= '0' && key <= '9' )
+ || ( key == ' ')
+ ) )
+ {
+
+ _list[_selectedItem] += key;
+ dirty = true;
+ }
+
+ } else {
+ // not editmode
+
+ switch (key) {
+ case '\n': // enter
+ case '\r':
+ if (_selectedItem >= 0) {
+ _editMode = true;
+ dirty = true;
+ }
+ break;
+ case 17: // up arrow
+ if (_selectedItem > 0)
+ _selectedItem--;
+ break;
+ case 18: // down arrow
+ if (_selectedItem < _list.size() - 1)
+ _selectedItem++;
+ break;
+ case 24: // pageup
+ _selectedItem -= _entriesPerPage - 1;
+ if (_selectedItem < 0)
+ _selectedItem = 0;
+ break;
+ case 25: // pagedown
+ _selectedItem += _entriesPerPage - 1;
+ if (_selectedItem >= _list.size() )
+ _selectedItem = _list.size() - 1;
+ break;
+ case 22: // home
+ _selectedItem = 0;
+ break;
+ case 23: // end
+ _selectedItem = _list.size() - 1;
+ break;
+ }
+
+ scrollToCurrent();
+ }
+
+ if (_editMode)
+ // re-add caret
+ _list[_selectedItem] += '_';
+
+ if (dirty || _selectedItem != oldSelectedItem)
+ draw();
+
+ if (_selectedItem != oldSelectedItem) {
+ // also draw scrollbar
+ _scrollBar->draw();
+ }
+
+}
+
+void ListWidget::lostFocusWidget()
+{
+ if (_editMode) {
+ // loose caret
+ _list[_selectedItem].deleteLastChar();
+ _editMode = false;
+ }
+
+ draw();
}
void ListWidget::handleCommand(CommandSender *sender, uint32 cmd, uint32 data)
@@ -119,7 +222,25 @@ void ListWidget::drawWidget(bool hilite)
} else
buffer = "";
buffer += _list[pos];
+
gui->drawString(buffer, _x+5, _y+2 + LINE_HEIGHT * i, _w - 10,
- (_selectedItem == pos) ? gui->_textcolorhi : gui->_textcolor);
+ (_selectedItem == pos && _hasFocus) ? gui->_textcolorhi : gui->_textcolor);
+ }
+}
+
+void ListWidget::scrollToCurrent() {
+
+ // Only do something if the current item is not in our view port
+ if (_selectedItem < _currentPos) {
+ // it's above our view
+ _currentPos = _selectedItem;
+ } else if (_selectedItem >= _currentPos + _entriesPerPage ) {
+ // it's below our view
+ _currentPos = _selectedItem - _entriesPerPage + 1;
+ if (_currentPos < 0)
+ _currentPos = 0;
}
+
+ _scrollBar->_currentPos = _currentPos;
+ _scrollBar->recalc();
}
diff --git a/gui/ListWidget.h b/gui/ListWidget.h
index d3f7b7760d..5927d44492 100644
--- a/gui/ListWidget.h
+++ b/gui/ListWidget.h
@@ -37,6 +37,7 @@ class ListWidget : public Widget, public CommandReceiver {
protected:
StringList _list;
bool _editable;
+ bool _editMode;
int _numberingMode;
int _currentPos;
int _entriesPerPage;
@@ -57,6 +58,8 @@ public:
protected:
void drawWidget(bool hilite);
+ void lostFocusWidget();
+ void scrollToCurrent();
};
#endif
diff --git a/gui/dialog.cpp b/gui/dialog.cpp
index f17cf4bf65..ddeb45dc2b 100644
--- a/gui/dialog.cpp
+++ b/gui/dialog.cpp
@@ -73,11 +73,24 @@ void Dialog::draw()
void Dialog::handleMouseDown(int x, int y, int button)
{
- _focusedWidget = findWidget(x, y);
+ Widget *w;
+ w = findWidget(x, y);
- if (_focusedWidget) {
- _focusedWidget->handleMouseDown(x - _focusedWidget->_x, y - _focusedWidget->_y, button);
+ if (w != _focusedWidget) {
+ // The focus will change. Tell the old focused widget (if any)
+ // that it lost the focus.
+ if (_focusedWidget)
+ _focusedWidget->lostFocus();
+
+ // Tell the new focused widget (if any) that it just gained the focus.
+ if (w)
+ w->recievedFocus();
+
+ _focusedWidget = w;
}
+
+ if (_focusedWidget)
+ _focusedWidget->handleMouseDown(x - _focusedWidget->_x, y - _focusedWidget->_y, button);
}
void Dialog::handleMouseUp(int x, int y, int button)
@@ -88,8 +101,10 @@ void Dialog::handleMouseUp(int x, int y, int button)
w = _focusedWidget;
// Lose focus on mouseup unless the widget requested to retain the focus
- if (! (_focusedWidget->getFlags() & WIDGET_RETAIN_FOCUS ))
+ if (! (_focusedWidget->getFlags() & WIDGET_RETAIN_FOCUS )) {
+ _focusedWidget->lostFocus();
_focusedWidget = 0;
+ }
} else {
w = findWidget(x, y);
diff --git a/gui/util.cpp b/gui/util.cpp
index 26475a8392..11f3aa4716 100644
--- a/gui/util.cpp
+++ b/gui/util.cpp
@@ -163,6 +163,13 @@ String& String::operator +=(char c)
return *this;
}
+void String::deleteLastChar() {
+ if (_len > 0) {
+ _len--;
+ _str[_len]=0;
+ }
+}
+
void String::clear()
{
if (_str)
@@ -187,3 +194,4 @@ void String::ensureCapacity(int new_len, bool keep_old)
free(old_str);
}
}
+
diff --git a/gui/util.h b/gui/util.h
index c1bd9bbc77..4509a0bcb3 100644
--- a/gui/util.h
+++ b/gui/util.h
@@ -114,6 +114,7 @@ public:
const char *c_str() const { return _str; }
int size() const { return _len; }
+ void deleteLastChar();
void clear();
protected:
diff --git a/gui/widget.cpp b/gui/widget.cpp
index 4b8219cc08..fa31e2f6d2 100644
--- a/gui/widget.cpp
+++ b/gui/widget.cpp
@@ -25,7 +25,8 @@
Widget::Widget (Dialog *boss, int x, int y, int w, int h)
- : _type(0), _boss(boss), _x(x), _y(y), _w(w), _h(h), _id(0), _flags(0)
+ : _type(0), _boss(boss), _x(x), _y(y), _w(w), _h(h),
+ _id(0), _flags(0), _hasFocus(false)
{
// Insert into the widget list of the boss
_next = _boss->_firstWidget;
diff --git a/gui/widget.h b/gui/widget.h
index 4b72df1b42..e29936dd49 100644
--- a/gui/widget.h
+++ b/gui/widget.h
@@ -84,6 +84,7 @@ protected:
uint16 _w, _h;
uint16 _id;
uint16 _flags;
+ bool _hasFocus;
public:
Widget(Dialog *boss, int x, int y, int w, int h);
@@ -98,6 +99,8 @@ public:
virtual void handleKeyUp(char key, int modifiers) {}
virtual void handleTickle() {}
void draw();
+ void recievedFocus() { _hasFocus = true; recievedFocusWidget(); }
+ void lostFocus() { _hasFocus = false; lostFocusWidget(); }
void setFlags(int flags) { _flags |= flags; }
void clearFlags(int flags) { _flags &= ~flags; }
@@ -105,6 +108,9 @@ public:
protected:
virtual void drawWidget(bool hilite) {}
+
+ virtual void recievedFocusWidget() {}
+ virtual void lostFocusWidget() {}
};