From f11a61a36fa5e21b0c6c2362af2952a3f87408a0 Mon Sep 17 00:00:00 2001
From: Bent Bisballe Nyeng <deva@aasimon.org>
Date: Sat, 14 Nov 2015 18:36:55 +0100
Subject: Refactor ScrollBar, and fix keyboard navigation in listbox.

---
 plugingui/listboxbasic.cc |  67 ++++++++------
 plugingui/listboxbasic.h  |  22 +++--
 plugingui/scrollbar.cc    | 226 +++++++++++++++++++++++++---------------------
 plugingui/scrollbar.h     |  57 ++++++------
 4 files changed, 199 insertions(+), 173 deletions(-)

(limited to 'plugingui')

diff --git a/plugingui/listboxbasic.cc b/plugingui/listboxbasic.cc
index 0d854ab..4f66046 100644
--- a/plugingui/listboxbasic.cc
+++ b/plugingui/listboxbasic.cc
@@ -31,12 +31,6 @@
 
 namespace GUI {
 
-void scrolled(void *ptr)
-{
-	ListBoxBasic *l = (ListBoxBasic *)ptr;
-	l->repaintEvent(NULL);
-}
-
 ListBoxBasic::ListBoxBasic(Widget *parent)
 	: Widget(parent)
 	, scroll(this)
@@ -45,7 +39,8 @@ ListBoxBasic::ListBoxBasic(Widget *parent)
 	scroll.move(0,0);
 	scroll.resize(18, 100);
 
-	scroll.registerValueChangeHandler(scrolled, this);
+	CONNECT(&scroll, valueChangeNotifier,
+	        this, &ListBoxBasic::onScrollBarValueChange);
 
 	padding = 4;
 	btn_size = 18;
@@ -61,10 +56,14 @@ ListBoxBasic::~ListBoxBasic()
 void ListBoxBasic::setSelection(int index)
 {
 	selected = index;
+	if(marked == -1)
+	{
+		marked = index;
+	}
 	valueChangedNotifier();
 }
 
-void ListBoxBasic::addItem(std::string name, std::string value)
+void ListBoxBasic::addItem(const std::string& name, const std::string& value)
 {
 	std::vector<ListBoxBasic::Item> items;
 	ListBoxBasic::Item item;
@@ -74,7 +73,7 @@ void ListBoxBasic::addItem(std::string name, std::string value)
 	addItems(items);
 }
 
-void ListBoxBasic::addItems(std::vector<ListBoxBasic::Item> &newItems)
+void ListBoxBasic::addItems(const std::vector<ListBoxBasic::Item>& newItems)
 {
 	for(auto& item : newItems)
 	{
@@ -83,11 +82,10 @@ void ListBoxBasic::addItems(std::vector<ListBoxBasic::Item> &newItems)
 
 	if(selected == -1)
 	{
-		setSelection((int)items.size() - 1);
+		//setSelection((int)items.size() - 1);
+		setSelection(0);
 	}
 
-	setSelection(0);
-
 	int numitems = height() / (font.textHeight() + padding);
 	scroll.setRange(numitems);
 	scroll.setMaximum(items.size());
@@ -98,6 +96,7 @@ void ListBoxBasic::clear()
 {
 	items.clear();
 	setSelection(-1);
+	marked = -1;
 	scroll.setValue(0);
 	repaintEvent(nullptr);
 }
@@ -140,7 +139,12 @@ void ListBoxBasic::clearSelectedValue()
 	setSelection(-1);
 }
 
-void ListBoxBasic::repaintEvent(RepaintEvent *e)
+void ListBoxBasic::onScrollBarValueChange(int value)
+{
+	repaintEvent(NULL);
+}
+
+void ListBoxBasic::repaintEvent(RepaintEvent* repaintEvent)
 {
 	Painter p(*this);
 
@@ -189,19 +193,20 @@ void ListBoxBasic::repaintEvent(RepaintEvent *e)
 	}
 }
 
-void ListBoxBasic::scrollEvent(ScrollEvent *e)
+void ListBoxBasic::scrollEvent(ScrollEvent* scrollEvent)
 {
-	scroll.scrollEvent(e);
+	// forward scroll event to scroll bar.
+	scroll.scrollEvent(scrollEvent);
 }
 
-void ListBoxBasic::keyEvent(KeyEvent *e)
+void ListBoxBasic::keyEvent(KeyEvent* keyEvent)
 {
-	if(e->direction != KeyEvent::Up)
+	if(keyEvent->direction != KeyEvent::Down)
 	{
 		return;
 	}
 
-	switch(e->keycode) {
+	switch(keyEvent->keycode) {
 	case KeyEvent::KeyUp:
 		if(marked == 0)
 		{
@@ -257,7 +262,7 @@ void ListBoxBasic::keyEvent(KeyEvent *e)
 		break;
 
 	case KeyEvent::KeyCharacter:
-		if(e->text == " ")
+		if(keyEvent->text == " ")
 		{
 			setSelection(marked);
 			//selectionNotifier();
@@ -276,13 +281,14 @@ void ListBoxBasic::keyEvent(KeyEvent *e)
 	repaintEvent(nullptr);
 }
 
-void ListBoxBasic::buttonEvent(ButtonEvent *e)
+void ListBoxBasic::buttonEvent(ButtonEvent* buttonEvent)
 {
-	if((e->x > ((int)width() - btn_size)) && (e->y < ((int)width() - 1)))
+	if((buttonEvent->x > ((int)width() - btn_size)) &&
+	   (buttonEvent->y < ((int)width() - 1)))
 	{
-		if(e->y > 0 && e->y < btn_size)
+		if(buttonEvent->y > 0 && buttonEvent->y < btn_size)
 		{
-			if(e->direction == ButtonEvent::Up)
+			if(buttonEvent->direction == ButtonEvent::Up)
 			{
 				return;
 			}
@@ -290,9 +296,10 @@ void ListBoxBasic::buttonEvent(ButtonEvent *e)
 			return;
 		}
 
-		if(e->y > ((int)height() - btn_size) && e->y < ((int)height() - 1))
+		if(buttonEvent->y > ((int)height() - btn_size) &&
+		   buttonEvent->y < ((int)height() - 1))
 		{
-			if(e->direction == ButtonEvent::Up)
+			if(buttonEvent->direction == ButtonEvent::Up)
 			{
 				return;
 			}
@@ -301,14 +308,14 @@ void ListBoxBasic::buttonEvent(ButtonEvent *e)
 		}
 	}
 
-	if(e->direction == ButtonEvent::Up)
+	if(buttonEvent->direction == ButtonEvent::Up)
 	{
 		int skip = scroll.value();
 		size_t yoffset = padding / 2;
 		for(int idx = skip; idx < (int)items.size(); idx++)
 		{
 			yoffset += font.textHeight() + padding;
-			if(e->y < (int)yoffset - (padding / 2))
+			if(buttonEvent->y < (int)yoffset - (padding / 2))
 			{
 				setSelection(idx);
 				marked = selected;
@@ -320,14 +327,14 @@ void ListBoxBasic::buttonEvent(ButtonEvent *e)
 		repaintEvent(nullptr);
 	}
 
-	if(e->direction != ButtonEvent::Up)
+	if(buttonEvent->direction != ButtonEvent::Up)
 	{
 		int skip = scroll.value();
 		size_t yoffset = padding / 2;
 		for(int idx = skip; idx < (int)items.size(); idx++)
 		{
 			yoffset += font.textHeight() + padding;
-			if(e->y < ((int)yoffset - (padding / 2)))
+			if(buttonEvent->y < ((int)yoffset - (padding / 2)))
 			{
 				marked = idx;
 				break;
@@ -337,7 +344,7 @@ void ListBoxBasic::buttonEvent(ButtonEvent *e)
 		repaintEvent(nullptr);
 	}
 
-	if(e->doubleclick)
+	if(buttonEvent->doubleclick)
 	{
 		selectionNotifier();
 	}
diff --git a/plugingui/listboxbasic.h b/plugingui/listboxbasic.h
index ef6aceb..1ada745 100644
--- a/plugingui/listboxbasic.h
+++ b/plugingui/listboxbasic.h
@@ -48,8 +48,8 @@ public:
 	ListBoxBasic(Widget *parent);
 	~ListBoxBasic();
 
-	void addItem(std::string name, std::string value);
-	void addItems(std::vector<Item> &items);
+	void addItem(const std::string& name, const std::string& value);
+	void addItems(const std::vector<Item>& items);
 
 	void clear();
 	bool selectItem(int index);
@@ -58,19 +58,23 @@ public:
 
 	void clearSelectedValue();
 
+	Notifier<> selectionNotifier;
+	Notifier<> clickNotifier;
+	Notifier<> valueChangedNotifier;
+
+	// From Widget:
+	virtual void resize(int w, int h) override;
+
+protected:
+	void onScrollBarValueChange(int value);
+
 	// From Widget:
 	bool isFocusable() override { return true; }
 	virtual void repaintEvent(RepaintEvent *e) override;
 	virtual void buttonEvent(ButtonEvent *e) override;
-	virtual void scrollEvent(ScrollEvent *e) override;
 	virtual void keyEvent(KeyEvent *e) override;
-	virtual void resize(int w, int h) override;
-
-	Notifier<> selectionNotifier;
-	Notifier<> clickNotifier;
-	Notifier<> valueChangedNotifier;
+	virtual void scrollEvent(ScrollEvent *e) override;
 
-private:
 	ScrollBar scroll;
 
 	Image bg_img;
diff --git a/plugingui/scrollbar.cc b/plugingui/scrollbar.cc
index c175720..7e6d47a 100644
--- a/plugingui/scrollbar.cc
+++ b/plugingui/scrollbar.cc
@@ -30,162 +30,180 @@
 
 #include "painter.h"
 
-GUI::ScrollBar::ScrollBar(GUI::Widget *parent)
-  : GUI::Widget(parent), bg_img(":widget_c.png")
+namespace GUI {
+
+ScrollBar::ScrollBar(Widget *parent)
+	: Widget(parent)
+	, bg_img(":widget_c.png")
 {
-  handler = NULL;
-  ptr = NULL;
 }
 
-void GUI::ScrollBar::setRange(int r)
+void ScrollBar::setRange(int r)
 {
-  DEBUG(scroll, "%d\n", r);
-  ran = r;
-  setValue(value());
-  repaintEvent(NULL);
+	rangeValue = r;
+	setValue(value());
+	repaintEvent(nullptr);
 }
 
-int GUI::ScrollBar::range()
+int ScrollBar::range()
 {
-  return ran;
+	return rangeValue;
 }
 
-void GUI::ScrollBar::setMaximum(int m)
+void ScrollBar::setMaximum(int m)
 {
-  DEBUG(scroll, "%d\n", m);
-  max = m;
-  if(max < ran) ran = max;
-  setValue(value());
-  repaintEvent(NULL);
+	maxValue = m;
+	if(maxValue < rangeValue)
+	{
+		rangeValue = maxValue;
+	}
+	setValue(value());
+	repaintEvent(nullptr);
 }
 
-int GUI::ScrollBar::maximum()
+int ScrollBar::maximum()
 {
-  return max;
+	return maxValue;
 }
 
-void GUI::ScrollBar::setValue(int value)
+void ScrollBar::addValue(int delta)
 {
-  if(value > max - ran) value = max - ran;
-  if(value < 0) value = 0;
+	setValue(value() + delta);
+}
 
-  if(val == value)
-  {
-	  return;
-  }
+void ScrollBar::setValue(int value)
+{
+	if(value > (maxValue - rangeValue))
+	{
+		value = maxValue - rangeValue;
+	}
 
-  val = value;
+	if(value < 0)
+	{
+		value = 0;
+	}
 
-  if(handler) handler(ptr);
+	if(currentValue == value)
+	{
+		return;
+	}
 
-  repaintEvent(NULL);
-}
+	currentValue = value;
 
-int GUI::ScrollBar::value()
-{
-  return val;
+	valueChangeNotifier(value);
+
+	repaintEvent(nullptr);
 }
 
-void GUI::ScrollBar::registerValueChangeHandler(void (*handler)(void *),
-                                                void *ptr)
+int ScrollBar::value()
 {
-  this->handler = handler;
-  this->ptr = ptr;
+	return currentValue;
 }
 
-static void drawArrow(GUI::Painter &p, int x, int y, int w, int h)
+//! Draw an up/down arrow at (x,y) with the bounding box size (w,h)
+//! If h is negative the arrow will point down, if positive it will point up.
+static void drawArrow(Painter &p, int x, int y, int w, int h)
 {
-  if(h < 0) y -= h;
+	if(h < 0)
+	{
+		y -= h;
+	}
 
-  p.drawLine(x, y, x+(w/2), y+h);
-  p.drawLine(x+(w/2), y+h, x+w, y);
+	p.drawLine(x, y, x + (w / 2), y + h);
+	p.drawLine(x + (w / 2), y + h, x + w, y);
 
-  y++;
-  p.drawLine(x, y, x+(w/2), y+h);
-  p.drawLine(x+(w/2), y+h, x+w, y);
+	++y;
+	p.drawLine(x, y, x + (w / 2), y + h);
+	p.drawLine(x + (w / 2), y + h, x + w, y);
 }
 
-void GUI::ScrollBar::repaintEvent(RepaintEvent *e)
+void ScrollBar::repaintEvent(RepaintEvent* repaintEvent)
 {
-  GUI::Painter p(*this);
+	Painter p(*this);
 
-  p.clear();
+	p.clear();
 
-  p.drawImageStretched(0, 0, bg_img, width(), height());
+	p.drawImageStretched(0, 0, bg_img, width(), height());
 
-  p.setColour(GUI::Colour(183.0/255.0, 219.0/255.0 , 255.0/255.0, 1));
-  if(!max) return;
+	p.setColour(Colour(183.0/255.0, 219.0/255.0 , 255.0/255.0, 1));
+	if(!maxValue)
+	{
+		return;
+	}
 
-  {
-  int h = height() - 2 * width() - 3;
-  int offset = width() + 2;
+	{
+		int h = height() - 2 * width() - 3;
+		int offset = width() + 2;
 
-  int y_val1 = (val * h) / max; 
-  int y_val2 = ((val + ran) * h) / max;  
+		int y_val1 = (currentValue * h) / maxValue;
+		int y_val2 = ((currentValue + rangeValue) * h) / maxValue;
 
-  p.drawFilledRectangle(2, y_val1 + offset, width() - 1, y_val2 + offset);
-  }
+		p.drawFilledRectangle(2, y_val1 + offset, width() - 1, y_val2 + offset);
+	}
 
-  p.drawLine(0, 0, 0, height());
+	p.drawLine(0, 0, 0, height());
 
-  drawArrow(p, width()/4, width()/4, width()/2, -1 * (width()/3));
-  p.drawLine(0, width(), width(), width());
+	drawArrow(p, width()/4, width()/4, width()/2, -1 * (width()/3));
+	p.drawLine(0, width(), width(), width());
 
-  drawArrow(p, width()/4, height() - width() + width()/4, width()/2, width()/3);
-  p.drawLine(0, height() - width(), width(), height() - width());
+	drawArrow(p, width()/4, height() - width() + width()/4, width()/2, width()/3);
+	p.drawLine(0, height() - width(), width(), height() - width());
 }
 
-void GUI::ScrollBar::scrollEvent(ScrollEvent *e)
+void ScrollBar::scrollEvent(ScrollEvent* scrollEvent)
 {
-  setValue(value() + e->delta);
+	setValue(value() + scrollEvent->delta);
 }
 
-void GUI::ScrollBar::mouseMoveEvent(MouseMoveEvent *e)
+void ScrollBar::mouseMoveEvent(MouseMoveEvent* mouseMoveEvent)
 {
-  if(!dragging) return;
+	if(!dragging)
+	{
+		return;
+	}
 
-  float delta = yoffset - e->y;
+	float delta = yOffset - mouseMoveEvent->y;
 
-  int h = height() - 2 * width() - 3;
-  delta /= (float)h / (float)max;
+	int h = height() - 2 * width() - 3;
+	delta /= (float)h / (float)maxValue;
 
-  int newval = value_offset - delta;
-  if(newval != value()) setValue(newval);
+	int newval = valueOffset - delta;
+	if(newval != value())
+	{
+		setValue(newval);
+	}
 }
 
-void GUI::ScrollBar::buttonEvent(ButtonEvent *e)
+void ScrollBar::buttonEvent(ButtonEvent* buttonEvent)
 {
-  if(e->y < (int)width() && e->y > 0) {
-    if(e->direction == ButtonEvent::Up) setValue(value() - 1);
-    return;
-  }
-
-  if(e->y > (int)height() - (int)width() && e->y < (int)height()) {
-    if(e->direction == ButtonEvent::Up) setValue(value() + 1);
-    return;
-  }
-
-  if(e->direction == ButtonEvent::Down) {
-    yoffset = e->y;
-    value_offset = value();
-  }
-
-  dragging = (e->direction == ButtonEvent::Down);
+	if((buttonEvent->y < (int)width()) && buttonEvent->y > 0)
+	{
+		if(buttonEvent->direction == ButtonEvent::Down)
+		{
+			addValue(-1);
+		}
+
+		return;
+	}
+
+	if((buttonEvent->y > ((int)height() - (int)width())) &&
+	   (buttonEvent->y < (int)height()))
+	{
+		if(buttonEvent->direction == ButtonEvent::Down)
+		{
+			addValue(1);
+		}
+
+		return;
+	}
+
+	if(buttonEvent->direction == ButtonEvent::Down)
+	{
+		yOffset = buttonEvent->y;
+		valueOffset = value();
+	}
+
+	dragging = (buttonEvent->direction == ButtonEvent::Down);
 }
 
-#ifdef TEST_SCROLLBAR
-//Additional dependency files
-//deps:
-//Required cflags (autoconf vars may be used)
-//cflags:
-//Required link options (autoconf vars may be used)
-//libs:
-#include "test.h"
-
-TEST_BEGIN;
-
-// TODO: Put some testcode here (see test.h for usable macros).
-
-TEST_END;
-
-#endif/*TEST_SCROLLBAR*/
+} // GUI::
diff --git a/plugingui/scrollbar.h b/plugingui/scrollbar.h
index 52acf9d..42e504e 100644
--- a/plugingui/scrollbar.h
+++ b/plugingui/scrollbar.h
@@ -24,52 +24,49 @@
  *  along with DrumGizmo; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
  */
-#ifndef __DRUMGIZMO_SCROLLBAR_H__
-#define __DRUMGIZMO_SCROLLBAR_H__
+#pragma once
 
 #include "widget.h"
 #include "image.h"
+#include "notifier.h"
 
 namespace GUI {
 
 class ScrollBar : public Widget {
+	friend class ListBoxBasic;
 public:
-  ScrollBar(Widget *parent);
+	ScrollBar(Widget *parent);
 
-  bool catchMouse() { return true; }
+	void setRange(int range);
+	int range();
 
-  void setRange(int range);
-  int range();
+	void setMaximum(int max);
+	int maximum();
 
-  void setMaximum(int max);
-  int maximum();
+	void addValue(int delta);
+	void setValue(int value);
+	int value();
 
-  void setValue(int value);
-  int value();
+	Notifier<int> valueChangeNotifier; // (int value)
 
-  void registerValueChangeHandler(void (*handler)(void *), void *ptr);
-
-  void repaintEvent(RepaintEvent *e);
-  void scrollEvent(ScrollEvent *e);
-  void buttonEvent(ButtonEvent *e);
-  void mouseMoveEvent(MouseMoveEvent *e);
+protected:
+	// From Widget:
+	bool catchMouse() override { return true; }
+	void scrollEvent(ScrollEvent* scrollEvent) override;
+	void repaintEvent(RepaintEvent* repaintEvent) override;
+	void buttonEvent(ButtonEvent* buttonEvent) override;
+	void mouseMoveEvent(MouseMoveEvent* mouseMoveEvent) override;
 
 private:
-  int max;
-  int val;
-  int ran;
-
-  int yoffset;
-  int value_offset;
-  bool dragging;
+	int maxValue;
+	int currentValue;
+	int rangeValue;
 
-  Image bg_img;
+	int yOffset;
+	int valueOffset;
+	bool dragging;
 
-  void (*handler)(void *);
-  void *ptr;
+	Image bg_img;
 };
 
-};
-
-
-#endif/*__DRUMGIZMO_SCROLLBAR_H__*/
+} // GUI::
-- 
cgit v1.2.3