summaryrefslogtreecommitdiff
path: root/src/gui/interface
diff options
context:
space:
mode:
authorSimon Robertshaw <simon@hardwired.org.uk>2013-03-22 14:14:17 (GMT)
committer Simon Robertshaw <simon@hardwired.org.uk>2013-03-22 14:14:17 (GMT)
commit9abe51526cac2634af0541c3de69834dd30e9f78 (patch)
tree6ae4deadfe00a83094b9d288d8c11d8ce823577a /src/gui/interface
parent2c311b9a36a88fadd96f3d39acb1ab2590835d81 (diff)
downloadpowder-9abe51526cac2634af0541c3de69834dd30e9f78.zip
powder-9abe51526cac2634af0541c3de69834dd30e9f78.tar.gz
Move all GUI source files into gui/
Diffstat (limited to 'src/gui/interface')
-rw-r--r--src/gui/interface/Appearance.cpp54
-rw-r--r--src/gui/interface/Appearance.h57
-rw-r--r--src/gui/interface/AvatarButton.cpp117
-rw-r--r--src/gui/interface/AvatarButton.h54
-rw-r--r--src/gui/interface/Border.h69
-rw-r--r--src/gui/interface/Button.cpp237
-rw-r--r--src/gui/interface/Button.h63
-rw-r--r--src/gui/interface/Checkbox.cpp104
-rw-r--r--src/gui/interface/Checkbox.h39
-rw-r--r--src/gui/interface/Colour.h24
-rw-r--r--src/gui/interface/Component.cpp244
-rw-r--r--src/gui/interface/Component.h224
-rw-r--r--src/gui/interface/ContextMenu.cpp99
-rw-r--r--src/gui/interface/ContextMenu.h40
-rw-r--r--src/gui/interface/DropDown.cpp197
-rw-r--r--src/gui/interface/DropDown.h41
-rw-r--r--src/gui/interface/Engine.cpp308
-rw-r--r--src/gui/interface/Engine.h108
-rw-r--r--src/gui/interface/Keys.h84
-rw-r--r--src/gui/interface/Label.cpp420
-rw-r--r--src/gui/interface/Label.h72
-rw-r--r--src/gui/interface/LuaProgressBar.h30
-rw-r--r--src/gui/interface/Panel.cpp457
-rw-r--r--src/gui/interface/Panel.h150
-rw-r--r--src/gui/interface/Platform.h71
-rw-r--r--src/gui/interface/Point.h146
-rw-r--r--src/gui/interface/ProgressBar.cpp81
-rw-r--r--src/gui/interface/ProgressBar.h21
-rw-r--r--src/gui/interface/RichLabel.cpp198
-rw-r--r--src/gui/interface/RichLabel.h39
-rw-r--r--src/gui/interface/SaveButton.cpp430
-rw-r--r--src/gui/interface/SaveButton.h83
-rw-r--r--src/gui/interface/ScrollPanel.cpp173
-rw-r--r--src/gui/interface/ScrollPanel.h32
-rw-r--r--src/gui/interface/Slider.cpp141
-rw-r--r--src/gui/interface/Slider.h40
-rw-r--r--src/gui/interface/Spinner.cpp37
-rw-r--r--src/gui/interface/Spinner.h23
-rw-r--r--src/gui/interface/Textbox.cpp707
-rw-r--r--src/gui/interface/Textbox.h108
-rw-r--r--src/gui/interface/Window.cpp558
-rw-r--r--src/gui/interface/Window.h135
42 files changed, 6315 insertions, 0 deletions
diff --git a/src/gui/interface/Appearance.cpp b/src/gui/interface/Appearance.cpp
new file mode 100644
index 0000000..a4c21d0
--- /dev/null
+++ b/src/gui/interface/Appearance.cpp
@@ -0,0 +1,54 @@
+#include <iostream>
+#include "Appearance.h"
+
+namespace ui
+{
+ Appearance::Appearance():
+ HorizontalAlign(AlignCentre),
+ VerticalAlign(AlignMiddle),
+
+ BackgroundHover(20, 20, 20),
+ BackgroundInactive(0, 0, 0),
+ BackgroundActive(255, 255, 255),
+ BackgroundDisabled(10, 10, 10),
+
+ TextHover(255, 255, 255),
+ TextInactive(255, 255, 255),
+ TextActive(0, 0, 0),
+ TextDisabled(100, 100, 100),
+
+ BorderHover(255, 255, 255),
+ BorderInactive(200, 200, 200),
+ BorderActive(235, 235, 235),
+ BorderDisabled(100, 100, 100),
+
+ Margin(1, 4),
+ Border(1),
+
+ icon(NoIcon),
+
+ texture(NULL)
+ {};
+
+ VideoBuffer * Appearance::GetTexture()
+ {
+ return texture;
+ }
+
+ void Appearance::SetTexture(VideoBuffer * texture)
+ {
+ if(this->texture)
+ delete this->texture;
+ if(texture)
+ this->texture = new VideoBuffer(texture);
+ else
+ this->texture = NULL;
+ }
+
+ Appearance::~Appearance()
+ {
+ if(texture)
+ delete texture;
+ }
+
+}
diff --git a/src/gui/interface/Appearance.h b/src/gui/interface/Appearance.h
new file mode 100644
index 0000000..1c1bb5a
--- /dev/null
+++ b/src/gui/interface/Appearance.h
@@ -0,0 +1,57 @@
+#ifndef APPEARANCE_H_
+#define APPEARANCE_H_
+
+#include "Border.h"
+#include "Colour.h"
+#include "graphics/Graphics.h"
+
+namespace ui
+{
+ class Appearance
+ {
+ private:
+ VideoBuffer * texture;
+ public:
+ enum HorizontalAlignment
+ {
+ AlignLeft, AlignCentre, AlignRight
+ };
+
+ enum VerticalAlignment
+ {
+ AlignTop, AlignMiddle, AlignBottom
+ };
+
+ VerticalAlignment VerticalAlign;
+ HorizontalAlignment HorizontalAlign;
+
+ ui::Colour BackgroundHover;
+ ui::Colour BackgroundInactive;
+ ui::Colour BackgroundActive;
+ ui::Colour BackgroundDisabled;
+
+ ui::Colour TextHover;
+ ui::Colour TextInactive;
+ ui::Colour TextActive;
+ ui::Colour TextDisabled;
+
+ ui::Colour BorderHover;
+ ui::Colour BorderInactive;
+ ui::Colour BorderActive;
+ ui::Colour BorderDisabled;
+
+ ui::Border Margin;
+
+ ui::Border Border;
+
+ Icon icon;
+
+ VideoBuffer * GetTexture();
+ void SetTexture(VideoBuffer * texture);
+
+ Appearance();
+ ~Appearance();
+ };
+}
+
+#endif
diff --git a/src/gui/interface/AvatarButton.cpp b/src/gui/interface/AvatarButton.cpp
new file mode 100644
index 0000000..e385c77
--- /dev/null
+++ b/src/gui/interface/AvatarButton.cpp
@@ -0,0 +1,117 @@
+#include <iostream>
+#include <typeinfo>
+
+#include "AvatarButton.h"
+#include "Format.h"
+#include "Engine.h"
+#include "client/Client.h"
+#include "client/requestbroker/RequestBroker.h"
+#include "graphics/Graphics.h"
+#include "ContextMenu.h"
+#include "Keys.h"
+
+namespace ui {
+
+AvatarButton::AvatarButton(Point position, Point size, std::string username):
+ Component(position, size),
+ name(username),
+ actionCallback(NULL),
+ avatar(NULL),
+ tried(false)
+{
+
+}
+
+AvatarButton::~AvatarButton()
+{
+ RequestBroker::Ref().DetachRequestListener(this);
+ if(avatar)
+ delete avatar;
+ if(actionCallback)
+ delete actionCallback;
+}
+
+void AvatarButton::Tick(float dt)
+{
+ if(!avatar && !tried && name.size() > 0)
+ {
+ tried = true;
+ RequestBroker::Ref().RetrieveAvatar(name, Size.X, Size.Y, this);
+ }
+}
+
+void AvatarButton::OnResponseReady(void * imagePtr)
+{
+ VideoBuffer * image = (VideoBuffer*)imagePtr;
+ if(image)
+ {
+ if(avatar)
+ delete avatar;
+ avatar = image;
+ }
+}
+
+void AvatarButton::Draw(const Point& screenPos)
+{
+ Graphics * g = ui::Engine::Ref().g;
+
+ if(avatar)
+ {
+ g->draw_image(avatar, screenPos.X, screenPos.Y, 255);
+ }
+}
+
+void AvatarButton::OnMouseUnclick(int x, int y, unsigned int button)
+{
+ if(button != 1)
+ {
+ return; //left click only!
+ }
+
+ if(isButtonDown)
+ {
+ isButtonDown = false;
+ DoAction();
+ }
+}
+
+void AvatarButton::OnContextMenuAction(int item)
+{
+ //Do nothing
+}
+
+void AvatarButton::OnMouseClick(int x, int y, unsigned int button)
+{
+ if(button == BUTTON_RIGHT)
+ {
+ if(menu)
+ menu->Show(GetScreenPos() + ui::Point(x, y));
+ }
+ else
+ {
+ isButtonDown = true;
+ }
+}
+
+void AvatarButton::OnMouseEnter(int x, int y)
+{
+ isMouseInside = true;
+}
+
+void AvatarButton::OnMouseLeave(int x, int y)
+{
+ isMouseInside = false;
+}
+
+void AvatarButton::DoAction()
+{
+ if(actionCallback)
+ actionCallback->ActionCallback(this);
+}
+
+void AvatarButton::SetActionCallback(AvatarButtonAction * action)
+{
+ actionCallback = action;
+}
+
+} /* namespace ui */
diff --git a/src/gui/interface/AvatarButton.h b/src/gui/interface/AvatarButton.h
new file mode 100644
index 0000000..26b4348
--- /dev/null
+++ b/src/gui/interface/AvatarButton.h
@@ -0,0 +1,54 @@
+#ifndef AVATARBUTTON_H_
+#define AVATARBUTTON_H_
+
+#include <string>
+
+#include "Component.h"
+#include "graphics/Graphics.h"
+#include "gui/interface/Colour.h"
+#include "client/requestbroker/RequestListener.h"
+
+namespace ui
+{
+class AvatarButton;
+class AvatarButtonAction
+{
+public:
+ virtual void ActionCallback(ui::AvatarButton * sender) {}
+ virtual ~AvatarButtonAction() {}
+};
+
+class AvatarButton : public Component, public RequestListener
+{
+ VideoBuffer * avatar;
+ std::string name;
+ bool tried;
+public:
+ AvatarButton(Point position, Point size, std::string username);
+ virtual ~AvatarButton();
+
+ virtual void OnMouseClick(int x, int y, unsigned int button);
+ virtual void OnMouseUnclick(int x, int y, unsigned int button);
+
+ virtual void OnMouseEnter(int x, int y);
+ virtual void OnMouseLeave(int x, int y);
+
+ virtual void OnContextMenuAction(int item);
+
+ virtual void Draw(const Point& screenPos);
+ virtual void Tick(float dt);
+
+ virtual void OnResponseReady(void * imagePtr);
+
+ virtual void DoAction();
+
+ void SetUsername(std::string username) { name = username; }
+ std::string GetUsername() { return name; }
+ void SetActionCallback(AvatarButtonAction * action);
+protected:
+ bool isMouseInside, isButtonDown;
+ AvatarButtonAction * actionCallback;
+};
+}
+#endif /* AVATARBUTTON_H_ */
+
diff --git a/src/gui/interface/Border.h b/src/gui/interface/Border.h
new file mode 100644
index 0000000..a1ceb81
--- /dev/null
+++ b/src/gui/interface/Border.h
@@ -0,0 +1,69 @@
+#pragma once
+#include "Platform.h"
+
+namespace ui
+{
+
+ struct Border
+ {
+#if ENABLE_FLOAT_UI
+# define BORDER_T float
+#else
+# define BORDER_T int
+#endif
+
+ BORDER_T Top;
+ BORDER_T Right;
+ BORDER_T Bottom;
+ BORDER_T Left;
+
+ Border(BORDER_T all):
+ Top(all),
+ Right(all),
+ Bottom(all),
+ Left(all)
+ {
+ }
+
+ Border(BORDER_T v, BORDER_T h):
+ Top(v),
+ Right(h),
+ Bottom(v),
+ Left(h)
+ {
+ }
+
+ Border(BORDER_T top, BORDER_T right, BORDER_T bottom, BORDER_T left):
+ Top(top),
+ Right(right),
+ Bottom(bottom),
+ Left(left)
+ {
+ }
+
+ inline bool operator == (const int& v) const
+ {
+ return (Top == v && Right == v && Bottom == v && Left == v);
+ }
+
+ inline bool operator == (const Border& v) const
+ {
+ return (Top == v.Top && Right == v.Right && Bottom == v.Bottom && Left == v.Left);
+ }
+
+ inline bool operator != (const Border& v) const
+ {
+ return (Top != v.Top || Right != v.Right || Bottom != v.Bottom || Left != v.Left);
+ }
+
+ inline void operator = (const Border& v)
+ {
+ Top = v.Top;
+ Right = v.Right;
+ Bottom = v.Bottom;
+ Left = v.Left;
+ }
+
+ };
+
+}
diff --git a/src/gui/interface/Button.cpp b/src/gui/interface/Button.cpp
new file mode 100644
index 0000000..3f08153
--- /dev/null
+++ b/src/gui/interface/Button.cpp
@@ -0,0 +1,237 @@
+#include <iostream>
+#include "gui/interface/Button.h"
+#include "graphics/Graphics.h"
+#include "Engine.h"
+#include "Misc.h"
+
+namespace ui {
+
+Button::Button(Point position, Point size, std::string buttonText, std::string toolTip):
+ Component(position, size),
+ ButtonText(buttonText),
+ isMouseInside(false),
+ isButtonDown(false),
+ isTogglable(false),
+ toggle(false),
+ actionCallback(NULL),
+ Enabled(true),
+ toolTip(toolTip)
+{
+ TextPosition();
+}
+
+void Button::TextPosition()
+{
+ buttonDisplayText = ButtonText;
+ if(buttonDisplayText.length())
+ {
+ if(Graphics::textwidth((char *)buttonDisplayText.c_str()) > Size.X - (Appearance.icon? 22 : 0))
+ {
+ int position = Graphics::textwidthx((char *)buttonDisplayText.c_str(), Size.X - (Appearance.icon? 38 : 22));
+ buttonDisplayText = buttonDisplayText.erase(position, buttonDisplayText.length()-position);
+ buttonDisplayText += "...";
+ }
+ }
+
+ Component::TextPosition(buttonDisplayText);
+}
+
+void Button::SetIcon(Icon icon)
+{
+ Appearance.icon = icon;
+ TextPosition();
+}
+
+void Button::SetText(std::string buttonText)
+{
+ ButtonText = buttonText;
+ TextPosition();
+}
+
+void Button::SetTogglable(bool togglable)
+{
+ toggle = false;
+ isTogglable = togglable;
+}
+
+bool Button::GetTogglable()
+{
+ return isTogglable;
+}
+
+TPT_NO_INLINE bool Button::GetToggleState()
+{
+ return toggle;
+}
+
+TPT_NO_INLINE void Button::SetToggleState(bool state)
+{
+ toggle = state;
+}
+
+void Button::Draw(const Point& screenPos)
+{
+ if(!drawn)
+ {
+ TextPosition();
+ drawn = true;
+ }
+ Graphics * g = ui::Engine::Ref().g;
+ Point Position = screenPos;
+ ui::Colour bgColour(0, 0, 0);
+
+ ui::Colour textColour = Appearance.TextInactive;
+ ui::Colour borderColour = Appearance.BorderInactive;
+ ui::Colour backgroundColour = Appearance.BackgroundInactive;
+
+ if(Enabled)
+ {
+ if(isButtonDown || (isTogglable && toggle))
+ {
+ textColour = Appearance.TextActive;
+ borderColour = Appearance.BorderActive;
+ backgroundColour = Appearance.BackgroundActive;
+ }
+ else if (isMouseInside)
+ {
+ textColour = Appearance.TextHover;
+ borderColour = Appearance.BorderHover;
+ backgroundColour = Appearance.BackgroundHover;
+ }
+ else
+ {
+ textColour = Appearance.TextInactive;
+ borderColour = Appearance.BorderInactive;
+ backgroundColour = Appearance.BackgroundInactive;
+ }
+ }
+ else
+ {
+ textColour = Appearance.TextDisabled;
+ borderColour = Appearance.BorderDisabled;
+ backgroundColour = Appearance.BackgroundDisabled;
+ }
+
+ bgColour = Appearance.BackgroundInactive;
+ g->fillrect(Position.X+1, Position.Y+1, Size.X-2, Size.Y-2, backgroundColour.Red, backgroundColour.Green, backgroundColour.Blue, backgroundColour.Alpha);
+ if(Appearance.Border == 1)
+ g->drawrect(Position.X, Position.Y, Size.X, Size.Y, borderColour.Red, borderColour.Green, borderColour.Blue, borderColour.Alpha);
+ else
+ {
+ if(Appearance.Border.Top)
+ g->draw_line(Position.X, Position.Y, Position.X+Size.X-1, Position.Y, borderColour.Red, borderColour.Green, borderColour.Blue, borderColour.Alpha);
+ if(Appearance.Border.Bottom)
+ g->draw_line(Position.X, Position.Y+Size.Y-1, Position.X+Size.X-1, Position.Y+Size.Y-1, borderColour.Red, borderColour.Green, borderColour.Blue, borderColour.Alpha);
+ if(Appearance.Border.Left)
+ g->draw_line(Position.X, Position.Y, Position.X, Position.Y+Size.Y-1, borderColour.Red, borderColour.Green, borderColour.Blue, borderColour.Alpha);
+ if(Appearance.Border.Right)
+ g->draw_line(Position.X+Size.X-1, Position.Y, Position.X+Size.X-1, Position.Y+Size.Y-1, borderColour.Red, borderColour.Green, borderColour.Blue, borderColour.Alpha);
+ }
+ g->drawtext(Position.X+textPosition.X, Position.Y+textPosition.Y, buttonDisplayText, textColour.Red, textColour.Green, textColour.Blue, textColour.Alpha);
+
+ bool iconInvert = (backgroundColour.Blue + (3*backgroundColour.Green) + (2*backgroundColour.Red))>544?true:false;
+
+ if(Appearance.icon)
+ {
+ if(Enabled)
+ if(isButtonDown || (isTogglable && toggle))
+ {
+ g->draw_icon(Position.X+iconPosition.X, Position.Y+iconPosition.Y, Appearance.icon, 255, iconInvert);
+ }
+ else
+ {
+ g->draw_icon(Position.X+iconPosition.X, Position.Y+iconPosition.Y, Appearance.icon, 255, iconInvert);
+ }
+ else
+ g->draw_icon(Position.X+iconPosition.X, Position.Y+iconPosition.Y, Appearance.icon, 180, iconInvert);
+ }
+}
+
+void Button::OnMouseUnclick(int x, int y, unsigned int button)
+{
+ if(button == 1)
+ {
+ if(isButtonDown)
+ {
+ isButtonDown = false;
+ DoAction();
+ }
+ }
+ else if(button == 3)
+ {
+ if(isAltButtonDown)
+ {
+ isAltButtonDown = false;
+ DoAltAction();
+ }
+ }
+}
+
+void Button::OnMouseClick(int x, int y, unsigned int button)
+{
+ if(!Enabled)
+ return;
+ if(button == 1)
+ {
+ if(isTogglable)
+ {
+ toggle = !toggle;
+ }
+ isButtonDown = true;
+ }
+ else if(button == 3)
+ {
+ isAltButtonDown = true;
+ }
+}
+
+void Button::OnMouseEnter(int x, int y)
+{
+ isMouseInside = true;
+ if(!Enabled)
+ return;
+ if(actionCallback)
+ actionCallback->MouseEnterCallback(this);
+ if(toolTip.length()>0 && GetParentWindow())
+ {
+ GetParentWindow()->ToolTip(this, ui::Point(x, y), toolTip);
+ }
+}
+
+
+void Button::OnMouseLeave(int x, int y)
+{
+ isMouseInside = false;
+ isButtonDown = false;
+}
+
+void Button::DoAction()
+{
+ if(!Enabled)
+ return;
+ if(actionCallback)
+ actionCallback->ActionCallback(this);
+}
+
+void Button::DoAltAction()
+{
+ if(!Enabled)
+ return;
+ if(actionCallback)
+ actionCallback->AltActionCallback(this);
+}
+
+void Button::SetActionCallback(ButtonAction * action)
+{
+ if(actionCallback)
+ delete actionCallback;
+ actionCallback = action;
+}
+
+Button::~Button()
+{
+ if(actionCallback)
+ delete actionCallback;
+}
+
+} /* namespace ui */
diff --git a/src/gui/interface/Button.h b/src/gui/interface/Button.h
new file mode 100644
index 0000000..05f466d
--- /dev/null
+++ b/src/gui/interface/Button.h
@@ -0,0 +1,63 @@
+#ifndef BUTTON_H_
+#define BUTTON_H_
+
+#include <string>
+#include "Misc.h"
+#include "Component.h"
+#include "Colour.h"
+
+namespace ui
+{
+class Button;
+class ButtonAction
+{
+public:
+ virtual void ActionCallback(ui::Button * sender) {}
+ virtual void AltActionCallback(ui::Button * sender) {}
+ virtual void MouseEnterCallback(ui::Button * sender) {}
+ virtual ~ButtonAction() {}
+};
+
+class Button : public Component
+{
+public:
+ Button(Point position = Point(0, 0), Point size = Point(0, 0), std::string buttonText = "", std::string toolTip = "");
+ virtual ~Button();
+
+ bool Toggleable;
+ bool Enabled;
+
+ virtual void OnMouseClick(int x, int y, unsigned int button);
+ virtual void OnMouseUnclick(int x, int y, unsigned int button);
+ //virtual void OnMouseUp(int x, int y, unsigned int button);
+
+ virtual void OnMouseEnter(int x, int y);
+ virtual void OnMouseLeave(int x, int y);
+
+ virtual void Draw(const Point& screenPos);
+
+ virtual void TextPosition();
+ inline bool GetState() { return state; }
+ virtual void DoAction(); //action of button what ever it may be
+ virtual void DoAltAction(); //action of button what ever it may be
+ void SetTogglable(bool isTogglable);
+ bool GetTogglable();
+ TPT_NO_INLINE bool GetToggleState();
+ TPT_NO_INLINE void SetToggleState(bool state);
+ void SetActionCallback(ButtonAction * action);
+ ButtonAction * GetActionCallback() { return actionCallback; }
+ void SetText(std::string buttonText);
+ void SetIcon(Icon icon);
+ inline std::string GetText() { return ButtonText; };
+protected:
+
+ std::string toolTip;
+ std::string buttonDisplayText;
+ std::string ButtonText;
+
+ bool isButtonDown, isAltButtonDown, state, isMouseInside, isTogglable, toggle;
+ ButtonAction * actionCallback;
+
+};
+}
+#endif /* BUTTON_H_ */
diff --git a/src/gui/interface/Checkbox.cpp b/src/gui/interface/Checkbox.cpp
new file mode 100644
index 0000000..7caf18b
--- /dev/null
+++ b/src/gui/interface/Checkbox.cpp
@@ -0,0 +1,104 @@
+#include "Checkbox.h"
+
+using namespace ui;
+
+Checkbox::Checkbox(ui::Point position, ui::Point size, std::string text, std::string toolTip):
+ Component(position, size),
+ text(text),
+ toolTip(toolTip),
+ isMouseOver(false),
+ checked(false),
+ actionCallback(NULL)
+{
+
+}
+
+void Checkbox::SetText(std::string text)
+{
+ this->text = text;
+}
+
+std::string Checkbox::GetText()
+{
+ return text;
+}
+
+void Checkbox::SetIcon(Icon icon)
+{
+ Appearance.icon = icon;
+ iconPosition.X = 16;
+ iconPosition.Y = 3;
+}
+
+void Checkbox::OnMouseClick(int x, int y, unsigned int button)
+{
+ if(checked)
+ {
+ checked = false;
+ }
+ else
+ {
+ checked = true;
+ }
+ if(actionCallback)
+ actionCallback->ActionCallback(this);
+}
+
+void Checkbox::OnMouseUp(int x, int y, unsigned int button)
+{
+
+}
+
+
+void Checkbox::OnMouseEnter(int x, int y)
+{
+ isMouseOver = true;
+ if(toolTip.length()>0 && GetParentWindow())
+ {
+ GetParentWindow()->ToolTip(this, ui::Point(x, y), toolTip);
+ }
+}
+
+void Checkbox::OnMouseLeave(int x, int y)
+{
+ isMouseOver = false;
+}
+
+void Checkbox::Draw(const Point& screenPos)
+{
+ Graphics * g = Engine::Ref().g;
+ if(checked)
+ {
+ g->fillrect(screenPos.X+5, screenPos.Y+5, 6, 6, 255, 255, 255, 255);
+ }
+ if(isMouseOver)
+ {
+ g->drawrect(screenPos.X+2, screenPos.Y+2, 12, 12, 255, 255, 255, 255);
+ g->fillrect(screenPos.X+5, screenPos.Y+5, 6, 6, 255, 255, 255, 170);
+ if (!Appearance.icon)
+ g->drawtext(screenPos.X+18, screenPos.Y+4, text, 255, 255, 255, 255);
+ else
+ g->draw_icon(screenPos.X+iconPosition.X, screenPos.Y+iconPosition.Y, Appearance.icon, 255);
+ }
+ else
+ {
+ g->drawrect(screenPos.X+2, screenPos.Y+2, 12, 12, 255, 255, 255, 200);
+ if (!Appearance.icon)
+ g->drawtext(screenPos.X+18, screenPos.Y+4, text, 255, 255, 255, 200);
+ else
+ g->draw_icon(screenPos.X+iconPosition.X, screenPos.Y+iconPosition.Y, Appearance.icon, 200);
+ }
+}
+
+void Checkbox::SetActionCallback(CheckboxAction * action)
+{
+ if(actionCallback)
+ delete actionCallback;
+ actionCallback = action;
+}
+
+Checkbox::~Checkbox() {
+ if(actionCallback)
+ delete actionCallback;
+}
+
diff --git a/src/gui/interface/Checkbox.h b/src/gui/interface/Checkbox.h
new file mode 100644
index 0000000..f82cef7
--- /dev/null
+++ b/src/gui/interface/Checkbox.h
@@ -0,0 +1,39 @@
+#ifndef CHECKBOX_H_
+#define CHECKBOX_H_
+
+#include <string>
+#include "Component.h"
+namespace ui
+{
+class Checkbox;
+class CheckboxAction
+{
+public:
+ virtual void ActionCallback(ui::Checkbox * sender) {}
+ virtual ~CheckboxAction() {}
+};
+class Checkbox: public ui::Component {
+ std::string text;
+ std::string toolTip;
+ bool checked;
+ bool isMouseOver;
+ CheckboxAction * actionCallback;
+public:
+ Checkbox(ui::Point position, ui::Point size, std::string text, std::string toolTip);
+ void SetText(std::string text);
+ std::string GetText();
+ void SetIcon(Icon icon);
+ void Draw(const Point& screenPos);
+ virtual void OnMouseEnter(int x, int y);
+ virtual void OnMouseLeave(int x, int y);
+ virtual void OnMouseClick(int x, int y, unsigned int button);
+ virtual void OnMouseUp(int x, int y, unsigned int button);
+ void SetActionCallback(CheckboxAction * action);
+ CheckboxAction * GetActionCallback() { return actionCallback; }
+ bool GetChecked() { return checked; }
+ void SetChecked(bool checked_) { checked = checked_; }
+ virtual ~Checkbox();
+};
+}
+
+#endif /* CHECKBOX_H_ */
diff --git a/src/gui/interface/Colour.h b/src/gui/interface/Colour.h
new file mode 100644
index 0000000..194b9c9
--- /dev/null
+++ b/src/gui/interface/Colour.h
@@ -0,0 +1,24 @@
+#ifndef COLOUR_H
+#define COLOUR_H
+
+namespace ui
+{
+class Colour
+{
+public:
+ unsigned char Red, Green, Blue, Alpha;
+ Colour(unsigned char red, unsigned char green, unsigned char blue):
+ Red(red), Green(green), Blue(blue), Alpha(255)
+ {
+ }
+ Colour(unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha):
+ Red(red), Green(green), Blue(blue), Alpha(alpha)
+ {
+ }
+ Colour()
+ {
+ }
+};
+}
+
+#endif
diff --git a/src/gui/interface/Component.cpp b/src/gui/interface/Component.cpp
new file mode 100644
index 0000000..6c4c548
--- /dev/null
+++ b/src/gui/interface/Component.cpp
@@ -0,0 +1,244 @@
+//#include "Platform.h"
+#include <iostream>
+#include "gui/interface/Component.h"
+#include "gui/interface/Engine.h"
+#include "gui/interface/Point.h"
+#include "gui/interface/Window.h"
+#include "gui/interface/Panel.h"
+#include "gui/interface/ContextMenu.h"
+
+using namespace ui;
+
+Component::Component(Window* parent_state):
+ parentstate_(parent_state),
+ _parent(NULL),
+ Position(Point(0,0)),
+ Size(Point(0,0)),
+ Locked(false),
+ Visible(true),
+ textPosition(0, 0),
+ textSize(0, 0),
+ iconPosition(0, 0),
+ drawn(false),
+ menu(NULL)
+{
+
+}
+
+Component::Component(Point position, Point size):
+ parentstate_(0),
+ _parent(NULL),
+ Position(position),
+ Size(size),
+ Locked(false),
+ Visible(true),
+ textPosition(0, 0),
+ textSize(0, 0),
+ iconPosition(0, 0),
+ drawn(false),
+ menu(NULL)
+{
+
+}
+
+Component::Component():
+ parentstate_(NULL),
+ _parent(NULL),
+ Position(Point(0,0)),
+ Size(Point(0,0)),
+ Locked(false),
+ Visible(true),
+ textPosition(0, 0),
+ textSize(0, 0),
+ iconPosition(0, 0),
+ drawn(false),
+ menu(NULL)
+{
+
+}
+
+void Component::Refresh()
+{
+ drawn = false;
+}
+
+void Component::TextPosition(std::string displayText)
+{
+
+ textPosition = ui::Point(0, 0);
+
+ int textWidth, textHeight = 10;
+ Graphics::textsize((char*)displayText.c_str(), textWidth, textHeight);
+ textSize.X = textWidth; textSize.Y = textHeight;
+ textHeight-=3;
+ textWidth-=1;
+ if(Appearance.icon)
+ {
+ textWidth += 13;
+ }
+
+ int textAreaWidth = Size.X-(Appearance.Margin.Right+Appearance.Margin.Left);
+ int textAreaHeight = Size.Y-(Appearance.Margin.Top+Appearance.Margin.Bottom);
+
+ switch(Appearance.VerticalAlign)
+ {
+ case ui::Appearance::AlignTop:
+ textPosition.Y = Appearance.Margin.Top+2;
+ break;
+ case ui::Appearance::AlignMiddle:
+ textPosition.Y = Appearance.Margin.Top+((textAreaHeight-textHeight)/2);
+ break;
+ case ui::Appearance::AlignBottom:
+ textPosition.Y = Size.Y-(textHeight+Appearance.Margin.Bottom);
+ break;
+ }
+
+ switch(Appearance.HorizontalAlign)
+ {
+ case ui::Appearance::AlignLeft:
+ textPosition.X = Appearance.Margin.Left;
+ break;
+ case ui::Appearance::AlignCentre:
+ textPosition.X = Appearance.Margin.Left+((textAreaWidth-textWidth)/2);
+ break;
+ case ui::Appearance::AlignRight:
+ textPosition.X = Size.X-(textWidth+Appearance.Margin.Right);
+ break;
+ }
+ if(Appearance.icon)
+ {
+ iconPosition = textPosition-ui::Point(0, 1);
+ textPosition.X += 15;
+ }
+}
+
+bool Component::IsFocused() const
+{
+ if(parentstate_)
+ return parentstate_->IsFocused(this);
+ return false;
+}
+
+void Component::SetParentWindow(Window* window)
+{
+ parentstate_ = window;
+}
+
+void Component::SetParent(Panel* new_parent)
+{
+ if(new_parent == NULL)
+ {
+ if(_parent != NULL)
+ {
+ // remove from current parent and send component to parent state
+ for(int i = 0; i < _parent->GetChildCount(); ++i)
+ {
+ if(_parent->GetChild(i) == this)
+ {
+ // remove ourself from parent component
+ _parent->RemoveChild(i, false);
+
+ // add ourself to the parent state
+ GetParentWindow()->AddComponent(this);
+
+ //done in this loop.
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ // remove from parent state (if in parent state) and place in new parent
+ if(GetParentWindow())
+ GetParentWindow()->RemoveComponent(this);
+ new_parent->children.push_back(this);
+ }
+ this->_parent = new_parent;
+}
+
+Point Component::GetScreenPos()
+{
+ Point newPos(0,0);
+ if(GetParentWindow())
+ newPos += GetParentWindow()->Position;
+ if(GetParent())
+ newPos += GetParent()->Position + GetParent()->ViewportPosition;
+ newPos += Position;
+ return newPos;
+}
+
+// ***** OVERRIDEABLES *****
+// Kept empty.
+
+void Component::OnContextMenuAction(int item)
+{
+
+}
+
+void Component::Draw(const Point& screenPos)
+{
+ drawn = true;
+}
+
+void Component::Tick(float dt)
+{
+}
+
+void Component::OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt)
+{
+}
+
+void Component::OnKeyRelease(int key, Uint16 character, bool shift, bool ctrl, bool alt)
+{
+}
+
+void Component::OnMouseClick(int localx, int localy, unsigned button)
+{
+}
+
+void Component::OnMouseDown(int x, int y, unsigned button)
+{
+}
+
+void Component::OnMouseHover(int localx, int localy)
+{
+}
+
+void Component::OnMouseMoved(int localx, int localy, int dx, int dy)
+{
+}
+
+void Component::OnMouseMovedInside(int localx, int localy, int dx, int dy)
+{
+}
+
+void Component::OnMouseEnter(int localx, int localy)
+{
+}
+
+void Component::OnMouseLeave(int localx, int localy)
+{
+}
+
+void Component::OnMouseUnclick(int localx, int localy, unsigned button)
+{
+}
+
+void Component::OnMouseUp(int x, int y, unsigned button)
+{
+}
+
+void Component::OnMouseWheel(int localx, int localy, int d)
+{
+}
+
+void Component::OnMouseWheelInside(int localx, int localy, int d)
+{
+}
+
+Component::~Component()
+{
+ if(menu)
+ delete menu;
+}
diff --git a/src/gui/interface/Component.h b/src/gui/interface/Component.h
new file mode 100644
index 0000000..c034952
--- /dev/null
+++ b/src/gui/interface/Component.h
@@ -0,0 +1,224 @@
+#pragma once
+
+#include "Appearance.h"
+#include "Point.h"
+#include "Window.h"
+#include "Platform.h"
+
+namespace ui
+{
+ class ContextMenu;
+ class Window;
+ class Panel;
+
+ /* class Component
+ *
+ * An interactive UI component that can be added to a state or an XComponent*.
+ * *See sys::XComponent
+ */
+ class Component
+ {
+ private:
+ Window* parentstate_;
+ Panel* _parent;
+ protected:
+ bool drawn;
+ ui::Point textPosition;
+ ui::Point textSize;
+ ui::Point iconPosition;
+ ui::ContextMenu * menu;
+ public:
+ Component(Window* parent_state);
+ Component(Point position, Point size);
+ Component();
+ virtual ~Component();
+
+ void* UserData;
+ inline Window* const GetParentWindow() const { return parentstate_; }
+ bool IsFocused() const;
+
+ void Invalidate() { drawn = false; }
+
+ Point Position;
+ Point Size;
+ bool Locked;
+ bool Visible;
+
+ ui::Appearance Appearance;
+ //virtual void SetAppearance(ui::Appearance);
+ //ui::Appearance GetAppearance();
+ virtual void TextPosition(std::string);
+
+ void Refresh();
+
+ Point GetScreenPos();
+
+ /* See the parent of this component.
+ * If new_parent is NULL, this component will have no parent. (THIS DOES NOT delete THE COMPONENT. See XComponent::RemoveChild)
+ */
+ void SetParentWindow(Window* window);
+ void SetParent(Panel* new_parent);
+
+ //Get the parent component.
+ inline Panel* const GetParent() const { return _parent; }
+
+ virtual void OnContextMenuAction(int item);
+
+ //UI functions:
+ /*
+ void Tick(float dt);
+ void Draw(const Point& screenPos);
+
+ void OnMouseHover(int localx, int localy);
+ void OnMouseMoved(int localx, int localy, int dx, int dy);
+ void OnMouseMovedInside(int localx, int localy, int dx, int dy);
+ void OnMouseEnter(int localx, int localy);
+ void OnMouseLeave(int localx, int localy);
+ void OnMouseDown(int x, int y, unsigned int button);
+ void OnMouseUp(int x, int y, unsigned int button);
+ void OnMouseClick(int localx, int localy, unsigned int button);
+ void OnMouseUnclick(int localx, int localy, unsigned int button);
+ void OnMouseWheel(int localx, int localy, int d);
+ void OnMouseWheelInside(int localx, int localy, int d);
+ void OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt);
+ void OnKeyRelease(int key, Uint16 character, bool shift, bool ctrl, bool alt);
+ */
+
+ ///
+ // Called: Every tick.
+ // Params:
+ // dt: The change in time.
+ ///
+ virtual void Tick(float dt);
+
+ ///
+ // Called: When ready to draw.
+ // Params:
+ // None
+ ///
+ virtual void Draw(const Point& screenPos);
+
+
+
+
+ ///
+ // Called: When the mouse is currently hovering over the item. (Called every tick)
+ // Params:
+ // localx: Local mouse X position.
+ // localy: Local mouse Y position.
+ ///
+ virtual void OnMouseHover(int localx, int localy);
+
+ ///
+ // Called: When the mouse moves.
+ // Params:
+ // localx: Local mouse X position.
+ // localy: Local mouse Y position.
+ // dx: Mouse X delta.
+ // dy: Mouse Y delta.
+ ///
+ virtual void OnMouseMoved(int localx, int localy, int dx, int dy);
+
+ ///
+ // Called: When the mouse moves.
+ // Params:
+ // localx: Local mouse X position.
+ // localy: Local mouse Y position.
+ // dx: Mouse X delta.
+ // dy: Mouse Y delta.
+ ///
+ virtual void OnMouseMovedInside(int localx, int localy, int dx, int dy);
+
+ ///
+ // Called: When the mouse moves on top of the item.
+ // Params:
+ // localx: Local mouse X position.
+ // localy: Local mouse Y position.
+ // dx: Mouse X delta.
+ // dy: Mouse Y delta.
+ ///
+ virtual void OnMouseEnter(int localx, int localy);
+
+ ///
+ // Called: When the mouse leaves the item.
+ // Params:
+ // localx: Local mouse X position.
+ // localy: Local mouse Y position.
+ ///
+ virtual void OnMouseLeave(int localx, int localy);
+
+ ///
+ // Called: When a mouse button is pressed.
+ // Params:
+ // x: X position of the mouse.
+ // y: Y position of the mouse.
+ // button: The button that is being held down.
+ ///
+ virtual void OnMouseDown(int x, int y, unsigned button);
+
+ ///
+ // Called: When a mouse button is released.
+ // Params:
+ // x: X position of the mouse.
+ // y: Y position of the mouse.
+ // button: The button that is being released.
+ ///
+ virtual void OnMouseUp(int x, int y, unsigned button);
+
+ ///
+ // Called: When a mouse button is pressed on top of the item.
+ // Params:
+ // x: X position of the mouse.
+ // y: Y position of the mouse.
+ // button: The button that is being held down.
+ ///
+ virtual void OnMouseClick(int localx, int localy, unsigned button);
+
+ ///
+ // Called: When a mouse button is released on top of the item.
+ // Params:
+ // x: X position of the mouse.
+ // y: Y position of the mouse.
+ // button: The button that is being released.
+ ///
+ virtual void OnMouseUnclick(int localx, int localy, unsigned button);
+
+ ///
+ // Called: When the mouse wheel moves/changes.
+ // Params:
+ // localx: Local mouse X position.
+ // localy: Local mouse Y position.
+ // d: The mouse wheel movement value.
+ ///
+ virtual void OnMouseWheel(int localx, int localy, int d);
+
+ ///
+ // Called: When the mouse wheel moves/changes on top of the item.
+ // Params:
+ // localx: Local mouse X position.
+ // localy: Local mouse Y position.
+ // d: The mouse wheel movement value.
+ ///
+ virtual void OnMouseWheelInside(int localx, int localy, int d);
+
+ ///
+ // Called: When a key is pressed.
+ // Params:
+ // key: The value of the key that is being pressed.
+ // shift: Shift key is down.
+ // ctrl: Control key is down.
+ // alt: Alternate key is down.
+ ///
+ virtual void OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt);
+
+ ///
+ // Called: When a key is released.
+ // Params:
+ // key: The value of the key that is being released.
+ // shift: Shift key is released.
+ // ctrl: Control key is released.
+ // alt: Alternate key is released.
+ ///
+ virtual void OnKeyRelease(int key, Uint16 character, bool shift, bool ctrl, bool alt);
+ };
+}
diff --git a/src/gui/interface/ContextMenu.cpp b/src/gui/interface/ContextMenu.cpp
new file mode 100644
index 0000000..0d34e19
--- /dev/null
+++ b/src/gui/interface/ContextMenu.cpp
@@ -0,0 +1,99 @@
+#include "ContextMenu.h"
+
+using namespace ui;
+
+class ContextMenu::ItemSelectedAction: public ButtonAction
+{
+ ContextMenu * window;
+ int item;
+public:
+ ItemSelectedAction(ContextMenu * window, int itemID): window(window), item(itemID) { }
+ virtual void ActionCallback(ui::Button *sender)
+ {
+ window->ActionCallback(sender, item);
+ }
+};
+
+ContextMenu::ContextMenu(Component * source):
+ Window(ui::Point(0, 0), ui::Point(0, 0)),
+ Appearance(source->Appearance),
+ source(source)
+{
+}
+
+void ContextMenu::Show(ui::Point position)
+{
+ for(int i = 0; i < buttons.size(); i++)
+ {
+ RemoveComponent(buttons[i]);
+ delete buttons[i];
+ }
+ buttons.clear();
+
+ Position = position;
+ Size.Y = items.size()*16;
+ Size.X = 100;
+
+ int currentY = 1;
+ for(int i = 0; i < items.size(); i++)
+ {
+ Button * tempButton = new Button(Point(1, currentY), Point(Size.X-2, 16), items[i].Text);
+ tempButton->Appearance = Appearance;
+ tempButton->Enabled = items[i].Enabled;
+ tempButton->SetActionCallback(new ItemSelectedAction(this, items[i].ID));
+ buttons.push_back(tempButton);
+ AddComponent(tempButton);
+ currentY += 15;
+ }
+
+ ui::Engine::Ref().ShowWindow(this);
+}
+
+void ContextMenu::ActionCallback(ui::Button *sender, int item)
+{
+ ui::Engine::Ref().CloseWindow();
+ Halt();
+ source->OnContextMenuAction(item);
+}
+
+void ContextMenu::OnMouseDown(int x, int y, unsigned button)
+{
+ if(!(x > Position.X && y > Position.Y && y < Position.Y+Size.Y && x < Position.X+Size.X)) //Clicked outside window
+ ui::Engine::Ref().CloseWindow();
+}
+
+void ContextMenu::SetItem(int id, std::string text)
+{
+ for(int i = 0; i < items.size(); i++)
+ {
+ if(items[i].ID == id)
+ {
+ items[i].Text = text;
+ break;
+ }
+ }
+}
+
+void ContextMenu::RemoveItem(int id)
+{
+ for(int i = 0; i < items.size(); i++)
+ {
+ if(items[i].ID == id)
+ {
+ items.erase(items.begin()+i);
+ break;
+ }
+ }
+}
+
+void ContextMenu::AddItem(ContextMenuItem item)
+{
+ items.push_back(item);
+}
+
+void ContextMenu::OnDraw()
+{
+ Graphics * g = ui::Engine::Ref().g;
+ g->fillrect(Position.X, Position.Y, Size.X, Size.Y, 100, 100, 100, 255);
+ g->drawrect(Position.X, Position.Y, Size.X, Size.Y, Appearance.BackgroundInactive.Red, Appearance.BackgroundInactive.Green, Appearance.BackgroundInactive.Blue, Appearance.BackgroundInactive.Alpha);
+} \ No newline at end of file
diff --git a/src/gui/interface/ContextMenu.h b/src/gui/interface/ContextMenu.h
new file mode 100644
index 0000000..e5549d3
--- /dev/null
+++ b/src/gui/interface/ContextMenu.h
@@ -0,0 +1,40 @@
+#ifndef The_Powder_Toy_ContextMenu_h
+#define The_Powder_Toy_ContextMenu_h
+
+#include "Window.h"
+#include "Appearance.h"
+#include "Button.h"
+
+namespace ui
+{
+
+class ContextMenuItem
+{
+public:
+ int ID;
+ std::string Text;
+ bool Enabled;
+ ContextMenuItem(std::string text, int id, bool enabled) : Text(text), ID(id), Enabled(enabled) {}
+};
+
+class ContextMenu: public ui::Window, public ButtonAction {
+ std::vector<Button*> buttons;
+ std::vector<ContextMenuItem> items;
+ bool isMouseInside;
+ ui::Component * source;
+public:
+ ui::Appearance Appearance;
+ class ItemSelectedAction;
+ ContextMenu(Component * source);
+ virtual void ActionCallback(ui::Button *sender, int item);
+ virtual void AddItem(ContextMenuItem item);
+ virtual void RemoveItem(int id);
+ virtual void SetItem(int id, std::string text);
+ virtual void Show(ui::Point position);
+ virtual void OnDraw();
+ virtual void OnMouseDown(int x, int y, unsigned button);
+ virtual ~ContextMenu() {}
+};
+}
+
+#endif \ No newline at end of file
diff --git a/src/gui/interface/DropDown.cpp b/src/gui/interface/DropDown.cpp
new file mode 100644
index 0000000..4c1d761
--- /dev/null
+++ b/src/gui/interface/DropDown.cpp
@@ -0,0 +1,197 @@
+#include <iostream>
+#include "Style.h"
+#include "Button.h"
+#include "DropDown.h"
+
+namespace ui {
+
+class ItemSelectedAction;
+class DropDownWindow: public ui::Window {
+ friend class ItemSelectedAction;
+ Appearance appearance;
+ DropDown * dropDown;
+ std::vector<Button> buttons;
+ bool isMouseInside;
+public:
+ class ItemSelectedAction: public ButtonAction
+ {
+ DropDownWindow * window;
+ std::string option;
+ public:
+ ItemSelectedAction(DropDownWindow * window, std::string option): window(window), option(option) { }
+ virtual void ActionCallback(ui::Button *sender)
+ {
+ ui::Engine::Ref().CloseWindow();
+ window->setOption(option);
+ window->SelfDestruct();
+ }
+ };
+ DropDownWindow(DropDown * dropDown):
+ Window(ui::Point(dropDown->Position.X+dropDown->GetParentWindow()->Position.X-5, dropDown->Position.Y+dropDown->GetParentWindow()->Position.Y-3), ui::Point(dropDown->Size.X+10, 1+dropDown->options.size()*16)),
+ dropDown(dropDown),
+ appearance(dropDown->Appearance)
+ {
+ int currentY = 1;
+ for(int i = 0; i < dropDown->options.size(); i++)
+ {
+ Button * tempButton = new Button(Point(1, currentY), Point(Size.X-2, 16), dropDown->options[i].first);
+ tempButton->Appearance = appearance;
+ if(i)
+ tempButton->Appearance.Border = ui::Border(0, 1, 1, 1);
+ tempButton->SetActionCallback(new ItemSelectedAction(this, dropDown->options[i].first));
+ AddComponent(tempButton);
+ currentY += 16;
+ }
+ }
+ virtual void OnDraw()
+ {
+ Graphics * g = ui::Engine::Ref().g;
+ g->clearrect(Position.X, Position.Y, Size.X, Size.Y);
+ }
+ void setOption(std::string option)
+ {
+ dropDown->SetOption(option);
+ if(dropDown->callback)
+ {
+ int optionIndex = 0;
+ for(optionIndex = 0; optionIndex < dropDown->options.size(); optionIndex++)
+ {
+ if(option == dropDown->options[optionIndex].first)
+ break;
+ }
+ dropDown->callback->OptionChanged(dropDown, dropDown->options[optionIndex]);
+ }
+ }
+ virtual void OnTryExit(ExitMethod method)
+ {
+ ui::Engine::Ref().CloseWindow();
+ SelfDestruct();
+ }
+ virtual ~DropDownWindow() {}
+};
+
+DropDown::DropDown(Point position, Point size):
+ Component(position, size),
+ isMouseInside(false),
+ optionIndex(-1),
+ callback(NULL)
+{
+}
+
+void DropDown::OnMouseClick(int x, int y, unsigned int button)
+{
+ DropDownWindow * newWindow = new DropDownWindow(this);
+ ui::Engine::Ref().ShowWindow(newWindow);
+}
+
+void DropDown::Draw(const Point& screenPos)
+{
+ if(!drawn)
+ {
+ if(optionIndex!=-1)
+ TextPosition(options[optionIndex].first);
+ drawn = true;
+ }
+ Graphics * g = ui::Engine::Ref().g;
+ Point Position = screenPos;
+
+ ui::Colour textColour = Appearance.TextInactive;
+ ui::Colour borderColour = Appearance.BorderInactive;
+ ui::Colour backgroundColour = Appearance.BackgroundInactive;
+
+ if (isMouseInside)
+ {
+ textColour = Appearance.TextHover;
+ borderColour = Appearance.BorderHover;
+ backgroundColour = Appearance.BackgroundHover;
+ }
+ else
+ {
+ textColour = Appearance.TextInactive;
+ borderColour = Appearance.BorderInactive;
+ backgroundColour = Appearance.BackgroundInactive;
+ }
+
+ g->fillrect(Position.X-1, Position.Y-1, Size.X+2, Size.Y+2, backgroundColour.Red, backgroundColour.Green, backgroundColour.Blue, backgroundColour.Alpha);
+ g->drawrect(Position.X, Position.Y, Size.X, Size.Y, borderColour.Red, borderColour.Green, borderColour.Blue, borderColour.Alpha);
+ if(optionIndex!=-1)
+ g->drawtext(Position.X+textPosition.X, Position.Y+textPosition.Y, options[optionIndex].first, textColour.Red, textColour.Green, textColour.Blue, textColour.Alpha);
+}
+
+void DropDown::OnMouseEnter(int x, int y)
+{
+ isMouseInside = true;
+}
+
+void DropDown::OnMouseLeave(int x, int y)
+{
+ isMouseInside = false;
+}
+ std::pair<std::string, int> DropDown::GetOption()
+ {
+ if(optionIndex!=-1)
+ {
+ return options[optionIndex];
+ }
+ return std::pair<std::string, int>("", -1);
+ }
+
+ void DropDown::SetOption(std::string option)
+ {
+ for(int i = 0; i < options.size(); i++)
+ {
+ if(options[i].first == option)
+ {
+ optionIndex = i;
+ TextPosition(options[optionIndex].first);
+ return;
+ }
+ }
+ }
+ void DropDown::SetOption(int option)
+ {
+ for(int i = 0; i < options.size(); i++)
+ {
+ if(options[i].second == option)
+ {
+ optionIndex = i;
+ TextPosition(options[optionIndex].first);
+ return;
+ }
+ }
+ }
+ void DropDown::AddOption(std::pair<std::string, int> option)
+ {
+ for(int i = 0; i < options.size(); i++)
+ {
+ if(options[i] == option)
+ return;
+ }
+ options.push_back(option);
+ }
+ void DropDown::RemoveOption(std::string option)
+ {
+ start:
+ for(int i = 0; i < options.size(); i++)
+ {
+ if(options[i].first == option)
+ {
+ if(i == optionIndex)
+ optionIndex = -1;
+ options.erase(options.begin()+i);
+ goto start;
+ }
+ }
+ }
+ void DropDown::SetOptions(std::vector<std::pair<std::string, int> > options)
+ {
+ this->options = options;
+ }
+
+
+DropDown::~DropDown() {
+ if(callback)
+ delete callback;
+}
+
+} /* namespace ui */
diff --git a/src/gui/interface/DropDown.h b/src/gui/interface/DropDown.h
new file mode 100644
index 0000000..c13fdf6
--- /dev/null
+++ b/src/gui/interface/DropDown.h
@@ -0,0 +1,41 @@
+#ifndef DROPDOWN_H_
+#define DROPDOWN_H_
+
+#include <utility>
+#include "Component.h"
+#include "Colour.h"
+
+namespace ui {
+
+class DropDown;
+class DropDownWindow;
+class DropDownAction
+{
+public:
+ virtual void OptionChanged(DropDown * sender, std::pair<std::string, int> newOption) {}
+ virtual ~DropDownAction() {}
+};
+class DropDown: public ui::Component {
+ friend class DropDownWindow;
+ bool isMouseInside;
+ int optionIndex;
+ DropDownAction * callback;
+ std::vector<std::pair<std::string, int> > options;
+public:
+ DropDown(Point position, Point size);
+ std::pair<std::string, int> GetOption();
+ void SetOption(int option);
+ void SetOption(std::string option);
+ void AddOption(std::pair<std::string, int> option);
+ void RemoveOption(std::string option);
+ void SetOptions(std::vector<std::pair<std::string, int> > options);
+ void SetActionCallback(DropDownAction * action) { callback = action;}
+ virtual void Draw(const Point& screenPos);
+ virtual void OnMouseClick(int x, int y, unsigned int button);
+ virtual void OnMouseEnter(int x, int y);
+ virtual void OnMouseLeave(int x, int y);
+ virtual ~DropDown();
+};
+
+} /* namespace ui */
+#endif /* DROPDOWN_H_ */
diff --git a/src/gui/interface/Engine.cpp b/src/gui/interface/Engine.cpp
new file mode 100644
index 0000000..6911c25
--- /dev/null
+++ b/src/gui/interface/Engine.cpp
@@ -0,0 +1,308 @@
+#include <iostream>
+#include <stack>
+#include <cstdio>
+#include <time.h>
+
+#include "Config.h"
+#include "gui/interface/Window.h"
+#include "gui/interface/Platform.h"
+#include "gui/interface/Engine.h"
+#include "graphics/Graphics.h"
+
+using namespace ui;
+using namespace std;
+
+Engine::Engine():
+ state_(NULL),
+ maxWidth(0),
+ maxHeight(0),
+ mouseb_(0),
+ mousex_(0),
+ mousey_(0),
+ mousexp_(0),
+ mouseyp_(0),
+ FpsLimit(60.0f),
+ windows(stack<Window*>()),
+ mousePositions(stack<Point>()),
+ lastBuffer(NULL),
+ prevBuffers(stack<pixel*>()),
+ windowTargetPosition(0, 0),
+ FrameIndex(0),
+ Fullscreen(false),
+ Scale(1),
+ FastQuit(1),
+ break_(false),
+ lastTick(0)
+{
+}
+
+Engine::~Engine()
+{
+ if(state_ != NULL)
+ delete state_;
+ //Dispose of any Windows.
+ while(!windows.empty())
+ {
+ delete windows.top();
+ windows.pop();
+ }
+ if (lastBuffer)
+ free(lastBuffer);
+}
+
+void Engine::Begin(int width, int height)
+{
+ //engine is now ready
+ running_ = true;
+
+ width_ = width;
+ height_ = height;
+}
+
+void Engine::Break()
+{
+ break_ = true;
+}
+
+void Engine::UnBreak()
+{
+ break_ = false;
+}
+
+void Engine::Exit()
+{
+ running_ = false;
+}
+
+void Engine::ShowWindow(Window * window)
+{
+ windowOpenState = 0.0f;
+ if(window->Position.X==-1)
+ {
+ window->Position.X = (width_-window->Size.X)/2;
+ }
+ if(window->Position.Y==-1)
+ {
+ window->Position.Y = (height_-window->Size.Y)/2;
+ }
+ /*if(window->Position.Y > 0)
+ {
+ windowTargetPosition = window->Position;
+ window->Position = Point(windowTargetPosition.X, height_);
+ }*/
+ if(state_)
+ {
+ if(lastBuffer)
+ {
+ prevBuffers.push(lastBuffer);
+ }
+ lastBuffer = (pixel*)malloc((width_ * height_) * PIXELSIZE);
+
+#ifndef OGLI
+ memcpy(lastBuffer, g->vid, (width_ * height_) * PIXELSIZE);
+#endif
+
+ windows.push(state_);
+ mousePositions.push(ui::Point(mousex_, mousey_));
+ }
+ if(state_)
+ state_->DoBlur();
+
+ state_ = window;
+
+}
+
+int Engine::CloseWindow()
+{
+ if(!windows.empty())
+ {
+ if (lastBuffer)
+ {
+ free(lastBuffer);
+ lastBuffer = NULL;
+ }
+ if(!prevBuffers.empty())
+ {
+ lastBuffer = prevBuffers.top();
+ prevBuffers.pop();
+ }
+ state_ = windows.top();
+ windows.pop();
+
+ if(state_)
+ state_->DoFocus();
+
+ ui::Point mouseState = mousePositions.top();
+ mousePositions.pop();
+ if(state_)
+ {
+ mousexp_ = mouseState.X;
+ mouseyp_ = mouseState.Y;
+ state_->DoMouseMove(mousex_, mousey_, mousex_ - mousexp_, mousey_ - mouseyp_);
+ mousexp_ = mousex_;
+ mouseyp_ = mousey_;
+ }
+ return 0;
+ }
+ else
+ {
+ state_ = NULL;
+ return 1;
+ }
+}
+
+/*void Engine::SetState(State * state)
+{
+ if(state_) //queue if currently in a state
+ statequeued_ = state;
+ else
+ {
+ state_ = state;
+ if(state_)
+ state_->DoInitialized();
+ }
+}*/
+
+void Engine::SetSize(int width, int height)
+{
+ width_ = width;
+ height_ = height;
+}
+
+void Engine::SetMaxSize(int width, int height)
+{
+ maxWidth = width;
+ maxHeight = height;
+}
+
+void Engine::Tick()
+{
+ if(state_ != NULL)
+ state_->DoTick(dt);
+
+
+ lastTick = clock();
+ if(windowOpenState<1.0f)
+ {
+ if(lastBuffer)
+ {
+ pixel * vid = g->vid;
+ g->vid = lastBuffer;
+ g->fillrect(0, 0, width_, height_, 0, 0, 0, 5);
+ g->vid = vid;
+
+ }
+ /*if(windowTargetPosition.Y < state_->Position.Y)
+ {
+ state_->Position.Y += windowTargetPosition.Y/20;
+ }*/
+ windowOpenState += 0.05f;//*dt;
+ }
+
+ /*if(statequeued_ != NULL)
+ {
+ if(state_ != NULL)
+ {
+ state_->DoExit();
+ delete state_;
+ state_ = NULL;
+ }
+ state_ = statequeued_;
+ statequeued_ = NULL;
+
+ if(state_ != NULL)
+ state_->DoInitialized();
+ }*/
+}
+
+void Engine::Draw()
+{
+ if(lastBuffer && !(state_->Position.X == 0 && state_->Position.Y == 0 && state_->Size.X == width_ && state_->Size.Y == height_))
+ {
+ g->Acquire();
+ g->Clear();
+#ifndef OGLI
+ memcpy(g->vid, lastBuffer, (width_ * height_) * PIXELSIZE);
+#endif
+ }
+ else
+ {
+ g->Clear();
+ }
+ if(state_)
+ state_->DoDraw();
+
+#ifdef DEBUG
+ char fpsText[512];
+ sprintf(fpsText, "FPS: %.2f, Delta: %.3f", fps, dt);
+ ui::Engine::Ref().g->drawtext(10, 10, fpsText, 255, 255, 255, 255);
+#endif
+ g->Finalise();
+ g->Release();
+ FrameIndex++;
+ FrameIndex %= 7200;
+}
+
+void Engine::SetFps(float fps)
+{
+ this->fps = fps;
+ if(FpsLimit > 2.0f)
+ this->dt = FpsLimit/fps;
+ else
+ this->dt = 1.0f;
+}
+
+void Engine::onKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt)
+{
+ if(state_)
+ state_->DoKeyPress(key, character, shift, ctrl, alt);
+}
+
+void Engine::onKeyRelease(int key, Uint16 character, bool shift, bool ctrl, bool alt)
+{
+ if(state_)
+ state_->DoKeyRelease(key, character, shift, ctrl, alt);
+}
+
+void Engine::onMouseClick(int x, int y, unsigned button)
+{
+ mouseb_ |= button;
+ if(state_)
+ state_->DoMouseDown(x, y, button);
+}
+
+void Engine::onMouseUnclick(int x, int y, unsigned button)
+{
+ mouseb_ &= ~button;
+ if(state_)
+ state_->DoMouseUp(x, y, button);
+}
+
+void Engine::onMouseMove(int x, int y)
+{
+ mousex_ = x;
+ mousey_ = y;
+ if(state_)
+ {
+ state_->DoMouseMove(x, y, mousex_ - mousexp_, mousey_ - mouseyp_);
+ }
+ mousexp_ = x;
+ mouseyp_ = y;
+}
+
+void Engine::onMouseWheel(int x, int y, int delta)
+{
+ if(state_)
+ state_->DoMouseWheel(x, y, delta);
+}
+
+void Engine::onResize(int newWidth, int newHeight)
+{
+ SetSize(newWidth, newHeight);
+}
+
+void Engine::onClose()
+{
+ if(state_)
+ state_->DoExit();
+}
diff --git a/src/gui/interface/Engine.h b/src/gui/interface/Engine.h
new file mode 100644
index 0000000..fb110e4
--- /dev/null
+++ b/src/gui/interface/Engine.h
@@ -0,0 +1,108 @@
+#pragma once
+
+#include <stack>
+#include "Singleton.h"
+#include "Platform.h"
+#include "graphics/Graphics.h"
+#include "Window.h"
+
+namespace ui
+{
+ class Window;
+
+ /* class Engine
+ *
+ * Controls the User Interface.
+ * Send user inputs to the Engine and the appropriate controls and components will interact.
+ */
+ class Engine: public Singleton<Engine>
+ {
+ public:
+ Engine();
+ ~Engine();
+
+ void ShowWindow(Window * window);
+ int CloseWindow();
+
+ void onMouseMove(int x, int y);
+ void onMouseClick(int x, int y, unsigned button);
+ void onMouseUnclick(int x, int y, unsigned button);
+ void onMouseWheel(int x, int y, int delta);
+ void onKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt);
+ void onKeyRelease(int key, Uint16 character, bool shift, bool ctrl, bool alt);
+ void onResize(int newWidth, int newHeight);
+ void onClose();
+
+ void Begin(int width, int height);
+ inline bool Running() { return running_; }
+ inline bool Broken() { return break_; }
+ inline int LastTick() { return lastTick; }
+ inline void LastTick(int tick) { lastTick = tick; }
+ void Exit();
+ void Break();
+ void UnBreak();
+
+ void SetFullscreen(bool fullscreen) { Fullscreen = fullscreen; }
+ inline bool GetFullscreen() { return Fullscreen; }
+ void SetScale(int scale) { Scale = scale; }
+ inline int GetScale() { return Scale; }
+ void SetFastQuit(bool fastquit) { FastQuit = fastquit; }
+ inline bool GetFastQuit() {return FastQuit; }
+
+ void Tick();
+ void Draw();
+
+ void SetFps(float fps);
+ inline float GetFps() { return fps; };
+
+ inline int GetMouseButton() { return mouseb_; }
+ inline int GetMouseX() { return mousex_; }
+ inline int GetMouseY() { return mousey_; }
+ inline int GetWidth() { return width_; }
+ inline int GetHeight() { return height_; }
+ inline int GetMaxWidth() { return maxWidth; }
+ inline int GetMaxHeight() { return maxHeight; }
+
+ TPT_NO_INLINE void SetMaxSize(int width, int height);
+
+ inline void SetSize(int width, int height);
+
+ //void SetState(Window* state);
+ //inline State* GetState() { return state_; }
+ inline Window* GetWindow() { return state_; }
+ float FpsLimit;
+ Graphics * g;
+ int Scale;
+ bool Fullscreen;
+
+ unsigned int FrameIndex;
+ private:
+ float dt;
+ float fps;
+ pixel * lastBuffer;
+ std::stack<pixel*> prevBuffers;
+ std::stack<Window*> windows;
+ std::stack<Point> mousePositions;
+ //Window* statequeued_;
+ Window* state_;
+ Point windowTargetPosition;
+ float windowOpenState;
+
+ bool running_;
+ bool break_;
+ bool FastQuit;
+
+ int lastTick;
+ int mouseb_;
+ int mousex_;
+ int mousey_;
+ int mousexp_;
+ int mouseyp_;
+ int width_;
+ int height_;
+
+ int maxWidth;
+ int maxHeight;
+ };
+
+}
diff --git a/src/gui/interface/Keys.h b/src/gui/interface/Keys.h
new file mode 100644
index 0000000..cd265f9
--- /dev/null
+++ b/src/gui/interface/Keys.h
@@ -0,0 +1,84 @@
+
+#if defined(USE_SDL)
+#include "SDL/SDL.h"
+#define KEY_UP SDLK_UP
+#define KEY_DOWN SDLK_DOWN
+#define KEY_RIGHT SDLK_RIGHT
+#define KEY_LEFT SDLK_LEFT
+#define KEY_HOME SDLK_HOME
+#define KEY_END SDLK_END
+#define KEY_BACKSPACE SDLK_BACKSPACE
+#define KEY_DELETE SDLK_DELETE
+#define KEY_TAB SDLK_TAB
+#define KEY_RETURN SDLK_RETURN
+#define KEY_ENTER SDLK_KP_ENTER
+#define KEY_ESCAPE SDLK_ESCAPE
+
+#define KEY_CTRL SDLK_LCTRL
+#define KEY_ALT SDLK_LALT
+#define KEY_SHIFT SDLK_LSHIFT
+
+#define KEY_MOD_NONE KMOD_NONE
+#define KEY_MOD_LSHIFT KMOD_LSHIFT
+#define KEY_MOD_RSHIFT KMOD_RSHIFT
+#define KEY_MOD_LCONTROL KMOD_LCTRL
+#define KEY_MOD_RCONTROL KMOD_RCTRL
+#define KEY_MOD_LALT KMOD_LALT
+#define KEY_MOD_RALT KMOD_RALT
+#define KEY_MOD_LMETA KMOD_LMETA
+#define KEY_MOD_RMETA KMOD_RMETA
+#define KEY_MOD_NUM KMOD_NUM
+#define KEY_MOD_CAPS KMOD_CAPS
+#define KEY_MOD_MODE KMOD_MODE
+#define KEY_MOD_RESERVED KMOD_RESERVED
+
+#define KEY_MOD_CONTROL KEY_MOD_RCONTROL | KEY_MOD_LCONTROL
+#define KEY_MOD_ALT KEY_MOD_RALT | KEY_MOD_LALT
+#define KEY_MOD_SHIFT KEY_MOD_RSHIFT | KEY_MOD_LSHIFT
+
+#define KEY_a SDLK_a
+#define KEY_d SDLK_d
+#define KEY_s SDLK_s
+#define KEY_w SDLK_w
+
+#define KEY_F1 SDLK_F1
+
+#define BUTTON_LEFT SDL_BUTTON_LEFT
+#define BUTTON_MIDDLE SDL_BUTTON_MIDDLE
+#define BUTTON_RIGHT SDL_BUTTON_RIGHT
+
+#else
+
+#define KEY_UP 1
+#define KEY_DOWN 2
+#define KEY_RIGHT 3
+#define KEY_LEFT 4
+#define KEY_HOME 5
+#define KEY_END 6
+#define KEY_BACKSPACE 7
+#define KEY_DELETE 8
+#define KEY_TAB 9
+#define KEY_RETURN 10
+#define KEY_ENTER 11
+#define KEY_ESCAPE 12
+
+#define KEY_CTRL 13
+#define KEY_ALT 14
+#define KEY_SHIFT 15
+
+#define KEY_MOD_CONTROL 16
+#define KEY_MOD_ALT 17
+#define KEY_MOD_SHIFT 18
+
+#define BUTTON_LEFT 19
+#define BUTTON_MIDDLE 20
+#define BUTTON_RIGHT 21
+
+#define KEY_a 22
+#define KEY_d 23
+#define KEY_s 24
+#define KEY_w 25
+
+#define KEY_F1 26
+
+#endif
diff --git a/src/gui/interface/Label.cpp b/src/gui/interface/Label.cpp
new file mode 100644
index 0000000..24b8035
--- /dev/null
+++ b/src/gui/interface/Label.cpp
@@ -0,0 +1,420 @@
+#include <string>
+#include "Config.h"
+#include "Point.h"
+#include "Label.h"
+#include "Keys.h"
+#include "ContextMenu.h"
+
+using namespace ui;
+
+Label::Label(Point position, Point size, std::string labelText):
+ Component(position, size),
+ text(labelText),
+ textColour(255, 255, 255),
+ selectionIndex0(-1),
+ selectionIndex1(-1),
+ selectionXL(-1),
+ selectionXH(-1),
+ multiline(false),
+ selecting(false),
+ autoHeight(size.Y==-1?true:false),
+ caret(-1)
+{
+ menu = new ContextMenu(this);
+ menu->AddItem(ContextMenuItem("Copy", 0, true));
+}
+
+Label::~Label()
+{
+
+}
+
+void Label::SetMultiline(bool status)
+{
+ multiline = status;
+ if(status)
+ {
+ updateMultiline();
+ updateSelection();
+ TextPosition(textLines);
+ }
+ else
+ {
+ TextPosition(text);
+ }
+}
+
+void Label::SetText(std::string text)
+{
+ this->text = text;
+ if(multiline)
+ {
+ updateMultiline();
+ updateSelection();
+ TextPosition(textLines);
+ }
+ else
+ {
+ TextPosition(text);
+ }
+}
+
+void Label::AutoHeight()
+{
+ bool oldAH = autoHeight;
+ autoHeight = true;
+ updateMultiline();
+ autoHeight = oldAH;
+}
+
+void Label::updateMultiline()
+{
+ int lines = 1;
+ if(text.length()>0)
+ {
+ char * rawText = new char[text.length()+1];
+ std::copy(text.begin(), text.end(), rawText);
+ rawText[text.length()] = 0;
+
+ char c, pc = 0;
+ int charIndex = 0;
+
+ int wordWidth = 0;
+ int lineWidth = 0;
+ char * wordStart = NULL;
+ while(c = rawText[charIndex++])
+ {
+ switch(c)
+ {
+ case ' ':
+ lineWidth += Graphics::CharWidth(c);
+ lineWidth += wordWidth;
+ wordWidth = 0;
+ break;
+ case '\n':
+ lineWidth = wordWidth = 0;
+ lines++;
+ break;
+ default:
+ wordWidth += Graphics::CharWidth(c);
+ break;
+ }
+ if(pc == ' ')
+ {
+ wordStart = &rawText[charIndex-2];
+ }
+ if ((c != ' ' || pc == ' ') && lineWidth + wordWidth >= Size.X-(Appearance.Margin.Left+Appearance.Margin.Right))
+ {
+ if(wordStart && *wordStart)
+ {
+ *wordStart = '\n';
+ if (lineWidth != 0)
+ lineWidth = wordWidth;
+ }
+ else if(!wordStart)
+ {
+ rawText[charIndex-1] = '\n';
+ lineWidth = 0;
+ }
+ wordWidth = 0;
+ wordStart = 0;
+ lines++;
+ }
+ pc = c;
+ }
+ if(autoHeight)
+ {
+ Size.Y = lines*12;
+ }
+ textLines = std::string(rawText);
+ delete[] rawText;
+ /*int currentWidth = 0;
+ char * lastSpace = NULL;
+ char * currentWord = rawText;
+ char * nextSpace;
+ while(true)
+ {
+ nextSpace = strchr(currentWord+1, ' ');
+ if(nextSpace)
+ nextSpace[0] = 0;
+ int width = Graphics::textwidth(currentWord);
+ if(width+currentWidth >= Size.X-(Appearance.Margin.Left+Appearance.Margin.Right))
+ {
+ currentWidth = width;
+ if(currentWord!=rawText)
+ {
+ currentWord[0] = '\n';
+ lines++;
+ }
+ }
+ else
+ currentWidth += width;
+ if(nextSpace)
+ nextSpace[0] = ' ';
+ if(!currentWord[0] || !currentWord[1] || !(currentWord = strchr(currentWord+1, ' ')))
+ break;
+ }
+ if(autoHeight)
+ {
+ Size.Y = lines*12;
+ }
+ textLines = std::string(rawText);
+ delete[] rawText;*/
+ }
+ else
+ {
+ if(autoHeight)
+ {
+ Size.Y = 12;
+ }
+ textLines = std::string("");
+ }
+}
+
+std::string Label::GetText()
+{
+ return this->text;
+}
+
+void Label::OnContextMenuAction(int item)
+{
+ switch(item)
+ {
+ case 0:
+ copySelection();
+ break;
+ }
+}
+
+void Label::OnMouseClick(int x, int y, unsigned button)
+{
+ if(button == BUTTON_RIGHT)
+ {
+ if(menu)
+ menu->Show(GetScreenPos() + ui::Point(x, y));
+ }
+ else
+ {
+ selecting = true;
+ if(multiline)
+ selectionIndex0 = Graphics::CharIndexAtPosition((char*)textLines.c_str(), x-textPosition.X, y-textPosition.Y);
+ else
+ selectionIndex0 = Graphics::CharIndexAtPosition((char*)text.c_str(), x-textPosition.X, y-textPosition.Y);
+ selectionIndex1 = selectionIndex0;
+
+ updateSelection();
+ }
+}
+
+void Label::copySelection()
+{
+ std::string currentText = text;
+
+ if(selectionIndex1 > selectionIndex0) {
+ ClipboardPush((char*)currentText.substr(selectionIndex0, selectionIndex1-selectionIndex0).c_str());
+ } else if(selectionIndex0 > selectionIndex1) {
+ ClipboardPush((char*)currentText.substr(selectionIndex1, selectionIndex0-selectionIndex1).c_str());
+ } else {
+ ClipboardPush((char*)currentText.c_str());
+ }
+}
+
+void Label::OnMouseUp(int x, int y, unsigned button)
+{
+ selecting = false;
+}
+
+void Label::OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt)
+{
+ if(ctrl && key == 'c')
+ {
+ copySelection();
+ }
+}
+
+void Label::OnMouseMoved(int localx, int localy, int dx, int dy)
+{
+ if(selecting)
+ {
+ if(multiline)
+ selectionIndex1 = Graphics::CharIndexAtPosition((char*)textLines.c_str(), localx-textPosition.X, localy-textPosition.Y);
+ else
+ selectionIndex1 = Graphics::CharIndexAtPosition((char*)text.c_str(), localx-textPosition.X, localy-textPosition.Y);
+ updateSelection();
+ }
+}
+
+void Label::Tick(float dt)
+{
+ if(!this->IsFocused() && (selecting || (selectionIndex0 != -1 && selectionIndex1 != -1)))
+ {
+ ClearSelection();
+ }
+}
+
+int Label::getLowerSelectionBound()
+{
+ return (selectionIndex0 > selectionIndex1) ? selectionIndex1 : selectionIndex0;
+}
+
+int Label::getHigherSelectionBound()
+{
+ return (selectionIndex0 > selectionIndex1) ? selectionIndex0 : selectionIndex1;
+}
+
+bool Label::HasSelection()
+{
+ if(selectionIndex0 != -1 && selectionIndex1 != -1 && selectionIndex0 != selectionIndex1)
+ return true;
+ return false;
+}
+
+void Label::ClearSelection()
+{
+ selecting = false;
+ selectionIndex0 = -1;
+ selectionIndex1 = -1;
+ updateSelection();
+}
+
+void Label::updateSelection()
+{
+ std::string currentText;
+
+ if(selectionIndex0 < 0) selectionIndex0 = 0;
+ if(selectionIndex0 > text.length()) selectionIndex0 = text.length();
+ if(selectionIndex1 < 0) selectionIndex1 = 0;
+ if(selectionIndex1 > text.length()) selectionIndex1 = text.length();
+
+ if(selectionIndex0 == -1 || selectionIndex1 == -1)
+ {
+ selectionXH = -1;
+ selectionXL = -1;
+
+ textFragments = std::string(currentText);
+ return;
+ }
+
+ if(multiline)
+ currentText = textLines;
+ else
+ currentText = text;
+
+ if(selectionIndex1 > selectionIndex0) {
+ selectionLineH = Graphics::PositionAtCharIndex((char*)currentText.c_str(), selectionIndex1, selectionXH, selectionYH);
+ selectionLineL = Graphics::PositionAtCharIndex((char*)currentText.c_str(), selectionIndex0, selectionXL, selectionYL);
+
+ textFragments = std::string(currentText);
+ //textFragments.insert(selectionIndex1, "\x0E");
+ //textFragments.insert(selectionIndex0, "\x0F\x01\x01\x01");
+ textFragments.insert(selectionIndex1, "\x01");
+ textFragments.insert(selectionIndex0, "\x01");
+ } else if(selectionIndex0 > selectionIndex1) {
+ selectionLineH = Graphics::PositionAtCharIndex((char*)currentText.c_str(), selectionIndex0, selectionXH, selectionYH);
+ selectionLineL = Graphics::PositionAtCharIndex((char*)currentText.c_str(), selectionIndex1, selectionXL, selectionYL);
+
+ textFragments = std::string(currentText);
+ //textFragments.insert(selectionIndex0, "\x0E");
+ //textFragments.insert(selectionIndex1, "\x0F\x01\x01\x01");
+ textFragments.insert(selectionIndex0, "\x01");
+ textFragments.insert(selectionIndex1, "\x01");
+ } else {
+ selectionXH = -1;
+ selectionXL = -1;
+
+ textFragments = std::string(currentText);
+ }
+
+ if(displayText.length())
+ {
+ displayText = tDisplayText;
+ if(selectionIndex1 > selectionIndex0) {
+ int tSelectionIndex1 = Graphics::CharIndexAtPosition((char*)displayText.c_str(), selectionXH, selectionYH);
+ int tSelectionIndex0 = Graphics::CharIndexAtPosition((char*)displayText.c_str(), selectionXL, selectionYL);
+
+ displayText.insert(tSelectionIndex1, "\x01");
+ displayText.insert(tSelectionIndex0, "\x01");
+ } else if(selectionIndex0 > selectionIndex1) {
+ int tSelectionIndex0 = Graphics::CharIndexAtPosition((char*)displayText.c_str(), selectionXH, selectionYH);
+ int tSelectionIndex1 = Graphics::CharIndexAtPosition((char*)displayText.c_str(), selectionXL, selectionYL);
+
+ displayText.insert(tSelectionIndex0, "\x01");
+ displayText.insert(tSelectionIndex1, "\x01");
+ }
+ }
+}
+
+void Label::SetDisplayText(std::string newText)
+{
+ displayText = newText;
+ tDisplayText = displayText;
+}
+
+void Label::Draw(const Point& screenPos)
+{
+ if(!drawn)
+ {
+ if(multiline)
+ {
+ TextPosition(textLines);
+ updateMultiline();
+ updateSelection();
+ }
+ else
+ TextPosition(text);
+ drawn = true;
+ }
+ Graphics * g = Engine::Ref().g;
+
+ std::string cDisplayText = displayText;
+
+ if(!cDisplayText.length())
+ {
+ if(selectionXL != -1 && selectionXH != -1)
+ {
+ cDisplayText = textFragments;
+ }
+ else
+ {
+ if(multiline)
+ cDisplayText = textLines;
+ else
+ cDisplayText = text;
+ }
+ }
+
+ if(multiline)
+ {
+ if(selectionXL != -1 && selectionXH != -1)
+ {
+ if(selectionLineH - selectionLineL > 0)
+ {
+ g->fillrect(screenPos.X+textPosition.X+selectionXL, (screenPos.Y+textPosition.Y-1)+selectionYL, textSize.X-(selectionXL), 10, 255, 255, 255, 255);
+ for(int i = 1; i < selectionLineH-selectionLineL; i++)
+ {
+ g->fillrect(screenPos.X+textPosition.X, (screenPos.Y+textPosition.Y-1)+selectionYL+(i*12), textSize.X, 10, 255, 255, 255, 255);
+ }
+ g->fillrect(screenPos.X+textPosition.X, (screenPos.Y+textPosition.Y-1)+selectionYH, selectionXH, 10, 255, 255, 255, 255);
+
+ } else {
+ g->fillrect(screenPos.X+textPosition.X+selectionXL, screenPos.Y+selectionYL+textPosition.Y-1, selectionXH-(selectionXL), 10, 255, 255, 255, 255);
+ }
+ g->drawtext(screenPos.X+textPosition.X, screenPos.Y+textPosition.Y, cDisplayText, textColour.Red, textColour.Green, textColour.Blue, 255);
+ }
+ else
+ {
+ g->drawtext(screenPos.X+textPosition.X, screenPos.Y+textPosition.Y, cDisplayText, textColour.Red, textColour.Green, textColour.Blue, 255);
+ }
+ } else {
+ if(selectionXL != -1 && selectionXH != -1)
+ {
+ g->fillrect(screenPos.X+textPosition.X+selectionXL, screenPos.Y+textPosition.Y-1, selectionXH-(selectionXL), 10, 255, 255, 255, 255);
+ g->drawtext(screenPos.X+textPosition.X, screenPos.Y+textPosition.Y, cDisplayText, textColour.Red, textColour.Green, textColour.Blue, 255);
+ }
+ else
+ {
+ g->drawtext(screenPos.X+textPosition.X, screenPos.Y+textPosition.Y, cDisplayText, textColour.Red, textColour.Green, textColour.Blue, 255);
+ }
+ }
+}
+
diff --git a/src/gui/interface/Label.h b/src/gui/interface/Label.h
new file mode 100644
index 0000000..d4e5088
--- /dev/null
+++ b/src/gui/interface/Label.h
@@ -0,0 +1,72 @@
+#ifndef LABEL_H
+#define LABEL_H
+
+#include <string>
+
+#include "Component.h"
+#include "PowderToy.h"
+#include "Colour.h"
+
+namespace ui
+{
+ class Label : public Component
+ {
+ protected:
+ std::string textFragments;
+ std::string textLines;
+ std::string displayText;
+ std::string tDisplayText;
+
+ std::string text;
+ Colour textColour;
+ int caret;
+ int selectionIndex0;
+ int selectionIndex1;
+
+ int selectionXL;
+ int selectionXH;
+ int selectionYL;
+ int selectionYH;
+ int selectionLineL;
+ int selectionLineH;
+
+ bool multiline;
+ bool selecting;
+ bool autoHeight;
+
+ void updateMultiline();
+ void updateSelection();
+
+ int getLowerSelectionBound();
+ int getHigherSelectionBound();
+
+ virtual void copySelection();
+ public:
+ //Label(Window* parent_state, std::string labelText);
+ Label(Point position, Point size, std::string labelText);
+ //Label(std::string labelText);
+ virtual ~Label();
+
+ virtual void SetMultiline(bool status);
+
+ virtual void SetText(std::string text);
+ virtual void SetDisplayText(std::string newText);
+ virtual std::string GetText();
+
+ virtual bool HasSelection();
+ virtual void ClearSelection();
+ virtual void AutoHeight();
+
+ void SetTextColour(Colour textColour) { this->textColour = textColour; }
+
+ virtual void OnContextMenuAction(int item);
+ virtual void OnMouseClick(int x, int y, unsigned button);
+ virtual void OnMouseUp(int x, int y, unsigned button);
+ virtual void OnMouseMoved(int localx, int localy, int dx, int dy);
+ virtual void OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt);
+ virtual void Draw(const Point& screenPos);
+ virtual void Tick(float dt);
+ };
+}
+
+#endif // LABEL_H
diff --git a/src/gui/interface/LuaProgressBar.h b/src/gui/interface/LuaProgressBar.h
new file mode 100644
index 0000000..dc2ef4e
--- /dev/null
+++ b/src/gui/interface/LuaProgressBar.h
@@ -0,0 +1,30 @@
+#pragma once
+
+extern "C" {
+ #include "lua.h"
+ #include "lauxlib.h"
+ #include "lualib.h"
+}
+
+#include "LuaLuna.h"
+#include "LuaComponent.h"
+
+namespace ui
+{
+ class ProgressBar;
+}
+
+class LuaScriptInterface;
+
+class LuaProgressBar: public LuaComponent
+{
+ ui::ProgressBar * progressBar;
+ int onValueChangedFunction;
+ int value(lua_State * l);
+public:
+ static const char className[];
+ static Luna<LuaProgressBar>::RegType methods[];
+
+ LuaProgressBar(lua_State * l);
+ ~LuaProgressBar();
+}; \ No newline at end of file
diff --git a/src/gui/interface/Panel.cpp b/src/gui/interface/Panel.cpp
new file mode 100644
index 0000000..3b19264
--- /dev/null
+++ b/src/gui/interface/Panel.cpp
@@ -0,0 +1,457 @@
+#pragma once
+#include <vector>
+//#include "Platform.h"
+
+#include "gui/interface/Panel.h"
+
+#include "gui/interface/Point.h"
+#include "gui/interface/Window.h"
+#include "gui/interface/Component.h"
+#include "graphics/Graphics.h"
+
+using namespace ui;
+
+Panel::Panel(Point position, Point size):
+ Component(position, size),
+ InnerSize(size),
+ ViewportPosition(0, 0),
+ mouseInside(false)
+{
+#ifdef OGLI
+ GLint lastVid;
+ glGetIntegerv(GL_FRAMEBUFFER_BINDING, &lastVid);
+
+ glEnable(GL_TEXTURE_2D);
+ glGenTextures(1, &myVidTex);
+ glBindTexture(GL_TEXTURE_2D, myVidTex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, XRES+BARSIZE, YRES+MENUSIZE, 0, GL_RGBA, GL_FLOAT, NULL);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
+
+ //FBO
+ glGenFramebuffers(1, &myVid);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, myVid);
+ glEnable(GL_BLEND);
+ glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, myVidTex, 0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // Reset framebuffer binding
+ glDisable(GL_TEXTURE_2D);
+
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, lastVid);
+#else
+ myVid = new pixel[(XRES+BARSIZE)*(YRES+MENUSIZE)];
+#endif
+}
+
+Panel::~Panel()
+{
+ for(unsigned i = 0; i < children.size(); ++i)
+ {
+ if( children[i] )
+ delete children[i];
+ }
+#ifdef OGLI
+ glDeleteTextures(1, &myVidTex);
+ glDeleteFramebuffers(1, &myVid);
+#else
+ delete[] myVid;
+#endif
+}
+
+void Panel::AddChild(Component* c)
+{
+ c->SetParent(this);
+ c->SetParentWindow(this->GetParentWindow());
+}
+
+int Panel::GetChildCount()
+{
+ return children.size();
+}
+
+Component* Panel::GetChild(unsigned idx)
+{
+ return children[idx];
+}
+
+void Panel::RemoveChild(Component* c)
+{
+ for(int i = 0; i < children.size(); ++i)
+ {
+ if(children[i] == c)
+ {
+ //remove child from parent. Does not free memory
+ children.erase(children.begin() + i);
+ if (this->GetParentWindow()->IsFocused(c))
+ this->GetParentWindow()->FocusComponent(NULL);
+ break;
+ }
+ }
+}
+
+void Panel::RemoveChild(unsigned idx, bool freeMem)
+{
+ if(freeMem)
+ delete children[idx];
+
+ children.erase(children.begin() + idx);
+}
+
+void Panel::Draw(const Point& screenPos)
+{
+
+ // draw ourself first
+ XDraw(screenPos);
+#ifdef OGLI
+ GLint lastVid;
+ glGetIntegerv(GL_FRAMEBUFFER_BINDING, &lastVid);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, myVid);
+ glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+#else
+ pixel * lastVid = ui::Engine::Ref().g->vid;
+ ui::Engine::Ref().g->vid = myVid;
+ std::fill(myVid, myVid+((XRES+BARSIZE)*(YRES+MENUSIZE)), 0);
+#endif
+
+ // attempt to draw all children
+ for(int i = 0; i < children.size(); ++i)
+ {
+ // the component must be visible
+ if(children[i]->Visible)
+ {
+ //check if the component is in the screen, draw if it is
+ if( children[i]->Position.X + ViewportPosition.X + children[i]->Size.X >= 0 &&
+ children[i]->Position.Y + ViewportPosition.Y + children[i]->Size.Y >= 0 &&
+ children[i]->Position.X + ViewportPosition.X < ui::Engine::Ref().GetWidth() &&
+ children[i]->Position.Y + ViewportPosition.Y < ui::Engine::Ref().GetHeight() )
+ {
+ Point scrpos = /*screenPos + */children[i]->Position + ViewportPosition;
+ children[i]->Draw(scrpos);
+ }
+ }
+ }
+
+#ifdef OGLI
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, lastVid);
+
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, myVidTex);
+
+ int x = screenPos.X, y = screenPos.Y;
+ int h = Size.Y, w = Size.X;
+
+ double texX = double(Size.X)/double(XRES+BARSIZE), texY = 1, texYB = 1-(double(Size.Y)/double(YRES+MENUSIZE));
+
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ glBegin(GL_QUADS);
+ glTexCoord2d(0, texYB);
+ glVertex2f(x, y+h);
+ glTexCoord2d(texX, texYB);
+ glVertex2f(x+w, y+h);
+ glTexCoord2d(texX, texY);
+ glVertex2f(x+w, y);
+ glTexCoord2d(0, texY);
+ glVertex2f(x, y);
+ glEnd();
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDisable(GL_TEXTURE_2D);
+#else
+ ui::Engine::Ref().g->vid = lastVid;
+
+ //dst=(pixel *)sdl_scrn->pixels+y*sdl_scrn->pitch/PIXELSIZE+x;
+ for (int row = 0; row < Size.Y; row++)
+ {
+ std::copy(myVid+(row*(XRES+BARSIZE)), myVid+(row*(XRES+BARSIZE))+Size.X, lastVid+((screenPos.Y+row)*(XRES+BARSIZE))+screenPos.X);
+ }
+#endif
+}
+
+void Panel::Tick(float dt)
+{
+ // tick ourself first
+ XTick(dt);
+
+ // tick our children
+ for(unsigned i = 0; i < children.size(); ++i)
+ children[i]->Tick(dt);
+}
+
+void Panel::OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt)
+{
+ XOnKeyPress(key, character, shift, ctrl, alt);
+}
+
+void Panel::OnKeyRelease(int key, Uint16 character, bool shift, bool ctrl, bool alt)
+{
+ XOnKeyRelease(key, character, shift, ctrl, alt);
+}
+
+void Panel::OnMouseClick(int localx, int localy, unsigned button)
+{
+ bool childclicked = false;
+
+ //check if clicked a child
+ for(int i = children.size()-1; i >= 0 ; --i)
+ {
+ //child must be unlocked
+ if(!children[i]->Locked)
+ {
+ //is mouse inside?
+ if( localx >= children[i]->Position.X + ViewportPosition.X &&
+ localy >= children[i]->Position.Y + ViewportPosition.Y &&
+ localx < children[i]->Position.X + ViewportPosition.X + children[i]->Size.X &&
+ localy < children[i]->Position.Y + ViewportPosition.Y + children[i]->Size.Y )
+ {
+ childclicked = true;
+ GetParentWindow()->FocusComponent(children[i]);
+ children[i]->OnMouseClick(localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y, button);
+ break;
+ }
+ }
+ }
+
+ //if a child wasn't clicked, send click to ourself
+ if(!childclicked)
+ {
+ XOnMouseClick(localx, localy, button);
+ GetParentWindow()->FocusComponent(this);
+ }
+}
+
+void Panel::OnMouseDown(int x, int y, unsigned button)
+{
+ XOnMouseDown(x, y, button);
+ for(int i = 0; i < children.size(); ++i)
+ {
+ if(!children[i]->Locked)
+ children[i]->OnMouseDown(x, y, button);
+ }
+}
+
+void Panel::OnMouseHover(int localx, int localy)
+{
+ // check if hovering on children
+ for(int i = children.size() - 1; i >= 0; --i)
+ {
+ if(!children[i]->Locked)
+ {
+ if( localx >= children[i]->Position.X &&
+ localy >= children[i]->Position.Y &&
+ localx < children[i]->Position.X + children[i]->Size.X &&
+ localy < children[i]->Position.Y + children[i]->Size.Y )
+ {
+ children[i]->OnMouseHover(localx - children[i]->Position.X, localy - children[i]->Position.Y);
+ break;
+ }
+ }
+ }
+
+ // always allow hover on parent (?)
+ XOnMouseHover(localx, localy);
+}
+
+void Panel::OnMouseMoved(int localx, int localy, int dx, int dy)
+{
+ XOnMouseMoved(localx, localy, dx, dy);
+ for(int i = 0; i < children.size(); ++i)
+ {
+ if(!children[i]->Locked)
+ children[i]->OnMouseMoved(localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y, dx, dy);
+ }
+}
+
+void Panel::OnMouseMovedInside(int localx, int localy, int dx, int dy)
+{
+ mouseInside = true;
+ for(int i = 0; i < children.size(); ++i)
+ {
+ if(!children[i]->Locked)
+ {
+ Point local (localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y)
+ , prevlocal (local.X - dx, local.Y - dy);
+
+ // mouse currently inside?
+ if( local.X >= 0 &&
+ local.Y >= 0 &&
+ local.X < children[i]->Size.X &&
+ local.Y < children[i]->Size.Y )
+ {
+ children[i]->OnMouseMovedInside(localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y, dx, dy);
+
+ // was the mouse outside?
+ if(!(prevlocal.X >= 0 &&
+ prevlocal.Y >= 0 &&
+ prevlocal.X < children[i]->Size.X &&
+ prevlocal.Y < children[i]->Size.Y ) )
+ {
+ children[i]->OnMouseEnter(local.X, local.Y);
+ }
+ }
+ // if not currently inside
+ else
+ {
+ // was the mouse inside?
+ if( prevlocal.X >= 0 &&
+ prevlocal.Y >= 0 &&
+ prevlocal.X < children[i]->Size.X &&
+ prevlocal.Y < children[i]->Size.Y )
+ {
+ children[i]->OnMouseLeave(local.X, local.Y);
+ }
+
+ }
+ }
+ }
+
+ // always allow hover on parent (?)
+ XOnMouseMovedInside(localx, localy, dx, dy);
+}
+
+void Panel::OnMouseEnter(int localx, int localy)
+{
+ mouseInside = true;
+ XOnMouseEnter(localx, localy);
+}
+
+void Panel::OnMouseLeave(int localx, int localy)
+{
+ mouseInside = false;
+ XOnMouseLeave(localx, localy);
+}
+
+void Panel::OnMouseUnclick(int localx, int localy, unsigned button)
+{
+ bool childunclicked = false;
+
+ //check if clicked a child
+ for(int i = children.size()-1; i >= 0 ; --i)
+ {
+ //child must be unlocked
+ if(!children[i]->Locked)
+ {
+ //is mouse inside?
+ if( localx >= children[i]->Position.X + ViewportPosition.X &&
+ localy >= children[i]->Position.Y + ViewportPosition.Y &&
+ localx < children[i]->Position.X + ViewportPosition.X + children[i]->Size.X &&
+ localy < children[i]->Position.Y + ViewportPosition.Y + children[i]->Size.Y )
+ {
+ childunclicked = true;
+ children[i]->OnMouseUnclick(localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y, button);
+ break;
+ }
+ }
+ }
+
+ //if a child wasn't clicked, send click to ourself
+ if(!childunclicked)
+ {
+ XOnMouseUnclick(localx, localy, button);
+ }
+}
+
+void Panel::OnMouseUp(int x, int y, unsigned button)
+{
+ XOnMouseUp(x, y, button);
+ for(int i = 0; i < children.size(); ++i)
+ {
+ if(!children[i]->Locked)
+ children[i]->OnMouseUp(x, y, button);
+ }
+}
+
+void Panel::OnMouseWheel(int localx, int localy, int d)
+{
+ XOnMouseWheel(localx, localy, d);
+ for(int i = 0; i < children.size(); ++i)
+ {
+ if(!children[i]->Locked)
+ children[i]->OnMouseWheel(localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y, d);
+ }
+}
+
+void Panel::OnMouseWheelInside(int localx, int localy, int d)
+{
+ XOnMouseWheelInside(localx, localy, d);
+ //check if clicked a child
+ for(int i = children.size()-1; i >= 0 ; --i)
+ {
+ //child must be unlocked
+ if(!children[i]->Locked)
+ {
+ //is mouse inside?
+ if( localx >= children[i]->Position.X + ViewportPosition.X &&
+ localy >= children[i]->Position.Y + ViewportPosition.Y &&
+ localx < children[i]->Position.X + ViewportPosition.X + children[i]->Size.X &&
+ localy < children[i]->Position.Y + ViewportPosition.Y + children[i]->Size.Y )
+ {
+ children[i]->OnMouseWheelInside(localx - children[i]->Position.X - ViewportPosition.X, localy - children[i]->Position.Y - ViewportPosition.Y, d);
+ break;
+ }
+ }
+ }
+}
+
+// ***** OVERRIDEABLES *****
+// Kept empty.
+
+void Panel::XDraw(const Point& screenPos)
+{
+}
+
+void Panel::XTick(float dt)
+{
+}
+
+void Panel::XOnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt)
+{
+}
+
+void Panel::XOnKeyRelease(int key, Uint16 character, bool shift, bool ctrl, bool alt)
+{
+}
+
+void Panel::XOnMouseClick(int localx, int localy, unsigned button)
+{
+}
+
+void Panel::XOnMouseDown(int x, int y, unsigned button)
+{
+}
+
+void Panel::XOnMouseHover(int localx, int localy)
+{
+}
+
+void Panel::XOnMouseMoved(int localx, int localy, int dx, int dy)
+{
+}
+
+void Panel::XOnMouseMovedInside(int localx, int localy, int dx, int dy)
+{
+}
+
+void Panel::XOnMouseEnter(int localx, int localy)
+{
+}
+
+void Panel::XOnMouseLeave(int localx, int localy)
+{
+}
+
+void Panel::XOnMouseUnclick(int localx, int localy, unsigned button)
+{
+}
+
+void Panel::XOnMouseUp(int x, int y, unsigned button)
+{
+}
+
+void Panel::XOnMouseWheel(int localx, int localy, int d)
+{
+}
+
+void Panel::XOnMouseWheelInside(int localx, int localy, int d)
+{
+}
diff --git a/src/gui/interface/Panel.h b/src/gui/interface/Panel.h
new file mode 100644
index 0000000..119be5d
--- /dev/null
+++ b/src/gui/interface/Panel.h
@@ -0,0 +1,150 @@
+#pragma once
+#include <vector>
+//#include "Platform.h"
+
+#include "gui/interface/Point.h"
+#include "gui/interface/Window.h"
+#include "gui/interface/Component.h"
+
+#ifdef OGLI
+#include "graphics/OpenGLHeaders.h"
+#endif
+
+
+class Graphics;
+namespace ui
+{
+ /* class XComponent
+ *
+ * An eXtension of the Component class.
+ * Adds the ability to have child components.
+ *
+ * See sys::Component
+ */
+
+class Component;
+ class Panel : public Component
+ {
+ public:
+ friend class Component;
+
+#ifdef OGLI
+ GLuint myVid, myVidTex;
+#else
+ pixel * myVid;
+#endif
+ ui::Point InnerSize;
+ ui::Point ViewportPosition;
+
+ Panel(Point position, Point size);
+ virtual ~Panel();
+
+ /* Add a child component.
+ * Similar to XComponent::SetParent
+ *
+ * If the component is already parented, then this will become the new parent.
+ */
+ void AddChild(Component* c);
+
+ // Remove child from component. This DOES NOT free the component from memory.
+ void RemoveChild(Component* c);
+
+ // Remove child from component. This WILL free the component from memory unless told otherwise.
+ void RemoveChild(unsigned idx, bool freeMem = true);
+
+ //Grab the number of children this component owns.
+ int GetChildCount();
+
+ //Get child of this component by index.
+ Component* GetChild(unsigned idx);
+
+ void Tick(float dt);
+ void Draw(const Point& screenPos);
+
+ void OnMouseHover(int localx, int localy);
+ void OnMouseMoved(int localx, int localy, int dx, int dy);
+ void OnMouseMovedInside(int localx, int localy, int dx, int dy);
+ void OnMouseEnter(int localx, int localy);
+ void OnMouseLeave(int localx, int localy);
+ void OnMouseDown(int x, int y, unsigned button);
+ void OnMouseUp(int x, int y, unsigned button);
+ void OnMouseClick(int localx, int localy, unsigned button);
+ void OnMouseUnclick(int localx, int localy, unsigned button);
+ void OnMouseWheel(int localx, int localy, int d);
+ void OnMouseWheelInside(int localx, int localy, int d);
+ void OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt);
+ void OnKeyRelease(int key, Uint16 character, bool shift, bool ctrl, bool alt);
+
+ protected:
+ // child components
+ std::vector<ui::Component*> children;
+ bool mouseInside;
+
+ //UI functions:
+ /*
+ void XTick(float dt);
+ void XDraw(const Point& screenPos);
+
+ void XOnMouseHover(int localx, int localy);
+ void XOnMouseMoved(int localx, int localy, int dx, int dy);
+ void XOnMouseMovedInside(int localx, int localy, int dx, int dy);
+ void XOnMouseEnter(int localx, int localy);
+ void XOnMouseLeave(int localx, int localy);
+ void XOnMouseDown(int x, int y, unsigned int button);
+ void XOnMouseUp(int x, int y, unsigned int button);
+ void XOnMouseClick(int localx, int localy, unsigned int button);
+ void XOnMouseUnclick(int localx, int localy, unsigned int button);
+ void XOnMouseWheel(int localx, int localy, int d);
+ void XOnMouseWheelInside(int localx, int localy, int d);
+ void XOnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt);
+ void XOnKeyRelease(int key, Uint16 character, bool shift, bool ctrl, bool alt);
+ */
+
+ // Overridable. Called by XComponent::Tick()
+ virtual void XTick(float dt);
+
+ // Overridable. Called by XComponent::Draw()
+ virtual void XDraw(const Point& screenPos);
+
+
+ // Overridable. Called by XComponent::XOnMouseHover()
+ virtual void XOnMouseHover(int localx, int localy);
+
+ // Overridable. Called by XComponent::OnMouseMoved()
+ virtual void XOnMouseMoved(int localx, int localy, int dx, int dy);
+
+ // Overridable. Called by XComponent::OnMouseMovedInside()
+ virtual void XOnMouseMovedInside(int localx, int localy, int dx, int dy);
+
+ // Overridable. Called by XComponent::OnMouseEnter()
+ virtual void XOnMouseEnter(int localx, int localy);
+
+ // Overridable. Called by XComponent::OnMouseLeave()
+ virtual void XOnMouseLeave(int localx, int localy);
+
+ // Overridable. Called by XComponent::OnMouseDown()
+ virtual void XOnMouseDown(int x, int y, unsigned button);
+
+ // Overridable. Called by XComponent::OnMouseUp()
+ virtual void XOnMouseUp(int x, int y, unsigned button);
+
+ // Overridable. Called by XComponent::OnMouseClick()
+ virtual void XOnMouseClick(int localx, int localy, unsigned button);
+
+ // Overridable. Called by XComponent::OnMouseUnclick()
+ virtual void XOnMouseUnclick(int localx, int localy, unsigned button);
+
+ // Overridable. Called by XComponent::OnMouseWheel()
+ virtual void XOnMouseWheel(int localx, int localy, int d);
+
+ // Overridable. Called by XComponent::OnMouseWheelInside()
+ virtual void XOnMouseWheelInside(int localx, int localy, int d);
+
+ // Overridable. Called by XComponent::OnKeyPress()
+ virtual void XOnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt);
+
+ // Overridable. Called by XComponent::OnKeyRelease()
+ virtual void XOnKeyRelease(int key, Uint16 character, bool shift, bool ctrl, bool alt);
+ };
+
+}
diff --git a/src/gui/interface/Platform.h b/src/gui/interface/Platform.h
new file mode 100644
index 0000000..5940303
--- /dev/null
+++ b/src/gui/interface/Platform.h
@@ -0,0 +1,71 @@
+#pragma once
+
+typedef unsigned short Uint16;
+
+/* ***** Primitive Types ***** */
+
+#ifndef NULL
+# define NULL 0
+#endif
+
+#include <climits>
+namespace sys
+{
+
+#if UCHAR_MAX == 0xFF //char
+ typedef signed char s8;
+ typedef unsigned char u8;
+#else
+# error No 8-Bit Integer supported.
+#endif
+#if USHRT_MAX == 0xFFFF //short
+ typedef signed short s16;
+ typedef unsigned short u16;
+#elif UINT_MAX == 0xFFFF
+ typedef signed int s16;
+ typedef unsigned int u16;
+#elif ULONG_MAX == 0xFFFF
+ typedef signed long s16;
+ typedef unsigned long u16;
+ #else
+ # error No 16-Bit Integer supported.
+ #endif
+ #if USHRT_MAX == 0xFFFFFFFF //int
+ typedef signed short s32;
+ typedef unsigned short u32;
+#elif UINT_MAX == 0xFFFFFFFF
+ typedef signed int s32;
+ typedef unsigned int u32;
+#elif ULONG_MAX == 0xFFFFFFFF
+ typedef signed long s32;
+ typedef unsigned long u32;
+ #else
+ # error No 32-Bit Integer supported.
+ #endif
+#if UINT_MAX == 0xFFFFFFFFFFFFFFFF //long
+ typedef signed int s64;
+ typedef unsigned int u64;
+#elif ULONG_MAX == 0xFFFFFFFFFFFFFFFF
+ typedef signed long s64;
+ typedef unsigned long u64;
+#elif ULLONG_MAX == 0xFFFFFFFFFFFFFFFF
+ typedef signed long long s64;
+ typedef unsigned long long u64;
+#else
+# pragma message("Warning: 64-bit not supported. s64 and u64 defined as 32-bit.")
+ typedef s32 s64;
+ typedef u32 u64;
+#endif
+//floating
+typedef float f32;
+typedef double f64;
+//misc
+typedef u8 byte;
+typedef u8 ubyte;
+typedef s8 sbyte;
+typedef s64 llong;
+typedef s64 sllong;
+typedef u64 ullong;
+typedef char* cstring;
+
+} //namespace sys
diff --git a/src/gui/interface/Point.h b/src/gui/interface/Point.h
new file mode 100644
index 0000000..d2eff6b
--- /dev/null
+++ b/src/gui/interface/Point.h
@@ -0,0 +1,146 @@
+#pragma once
+#include "Platform.h"
+
+namespace ui
+{
+
+//Lightweight 2D Int32/Float32 Point struct for UI
+struct Point
+{
+#if ENABLE_FLOAT_UI
+# define POINT_T float
+#else
+# define POINT_T int
+#endif
+
+ POINT_T X;
+ POINT_T Y;
+
+ Point(POINT_T x, POINT_T y)
+ : X(x)
+ , Y(y)
+ {
+ }
+
+ inline Point operator - () const
+ {
+ return Point(-X, -Y);
+ }
+
+ inline Point operator + (const Point& v) const
+ {
+ return Point(X + v.X, Y + v.Y);
+ }
+
+ inline Point operator + (const int v) const
+ {
+ return Point(X + v, Y + v);
+ }
+
+ inline Point operator - (const Point& v) const
+ {
+ return Point(X - v.X, Y - v.Y);
+ }
+
+ inline Point operator - (const int v) const
+ {
+ return Point(X - v, Y - v);
+ }
+
+ inline Point operator * (const Point& v) const
+ {
+ return Point(X * v.X, Y * v.Y);
+ }
+
+ inline Point operator * (int v) const
+ {
+ return Point(X * static_cast<POINT_T>(v), Y * static_cast<POINT_T>(v));
+ }
+
+ inline Point operator * (float v) const
+ {
+ return Point(X * static_cast<POINT_T>(v), Y * static_cast<POINT_T>(v));
+ }
+
+ inline Point operator / (const Point& v) const
+ {
+ return Point(X / v.X, Y / v.Y);
+ }
+
+ inline Point operator / (int v) const
+ {
+ return Point(X / static_cast<POINT_T>(v), Y / static_cast<POINT_T>(v));
+ }
+
+ inline Point operator / (float v) const
+ {
+ return Point(X / static_cast<POINT_T>(v), Y / static_cast<POINT_T>(v));
+ }
+
+ inline void operator += (const Point& v)
+ {
+ X += v.X;
+ Y += v.Y;
+ }
+
+ inline void operator -= (const Point& v)
+ {
+ X -= v.X;
+ Y -= v.Y;
+ }
+
+ inline void operator *= (const Point& v)
+ {
+ X *= v.X;
+ Y *= v.Y;
+ }
+
+ inline void operator *= (int v)
+ {
+ X *= static_cast<POINT_T>(v);
+ Y *= static_cast<POINT_T>(v);
+ }
+
+ inline void operator *= (float v)
+ {
+ X *= static_cast<POINT_T>(v);
+ Y *= static_cast<POINT_T>(v);
+ }
+
+ inline void operator /= (const Point& v)
+ {
+ X /= v.X;
+ Y /= v.Y;
+ }
+
+ inline void operator /= (int v)
+ {
+ X /= static_cast<POINT_T>(v);
+ Y /= static_cast<POINT_T>(v);
+ }
+
+ inline void operator /= (float v)
+ {
+ X /= static_cast<POINT_T>(v);
+ Y /= static_cast<POINT_T>(v);
+ }
+
+ inline bool operator == (const Point& v) const
+ {
+ return (X == v.X && Y == v.Y);
+ }
+
+ inline bool operator != (const Point& v) const
+ {
+ return (X != v.X || Y != v.Y);
+ }
+
+ inline void operator = (const Point& v)
+ {
+ X = v.X;
+ Y = v.Y;
+ }
+
+};
+
+}
diff --git a/src/gui/interface/ProgressBar.cpp b/src/gui/interface/ProgressBar.cpp
new file mode 100644
index 0000000..eda88f6
--- /dev/null
+++ b/src/gui/interface/ProgressBar.cpp
@@ -0,0 +1,81 @@
+#include "ProgressBar.h"
+#include "Style.h"
+
+using namespace ui;
+
+ProgressBar::ProgressBar(Point position, Point size, int startProgress, std::string startStatus):
+ Component(position, size),
+ intermediatePos(0.0f),
+ progressStatus(""),
+ progress(0)
+{
+ SetStatus(startStatus);
+ SetProgress(startProgress);
+}
+
+void ProgressBar::SetProgress(int progress)
+{
+ this->progress = progress;
+ if(this->progress > 100)
+ this->progress = 100;
+}
+
+int ProgressBar::GetProgress()
+{
+ return progress;
+}
+
+void ProgressBar::SetStatus(std::string status)
+{
+ progressStatus = status;
+}
+
+std::string ProgressBar::GetStatus()
+{
+ return progressStatus;
+}
+
+void ProgressBar::Draw(const Point & screenPos)
+{
+ Graphics * g = ui::Engine::Ref().g;
+
+ ui::Colour progressBarColour = style::Colour::WarningTitle;
+
+ g->drawrect(screenPos.X, screenPos.Y, Size.X, Size.Y, 255, 255, 255, 255);
+
+ if(progress!=-1)
+ {
+ if(progress > 0)
+ {
+ if(progress > 100)
+ progress = 100;
+ float size = float(Size.X-4)*(float(progress)/100.0f); // TIL...
+ size = std::min(std::max(size, 0.0f), float(Size.X-4));
+ g->fillrect(screenPos.X + 2, screenPos.Y + 2, size, Size.Y-4, progressBarColour.Red, progressBarColour.Green, progressBarColour.Blue, 255);
+ }
+ } else {
+ int size = 40, rsize = 0;
+ float position = float(Size.X-4)*(intermediatePos/100.0f);
+ if(position + size - 1 > Size.X-4)
+ {
+ size = (Size.X-4)-position+1;
+ rsize = 40-size;
+ }
+ g->fillrect(screenPos.X + 2 + position, screenPos.Y + 2, size, Size.Y-4, progressBarColour.Red, progressBarColour.Green, progressBarColour.Blue, 255);
+ if(rsize)
+ {
+ g->fillrect(screenPos.X + 2, screenPos.Y + 2, rsize, Size.Y-4, progressBarColour.Red, progressBarColour.Green, progressBarColour.Blue, 255);
+ }
+ }
+ if(progress<50)
+ g->drawtext(screenPos.X + ((Size.X-Graphics::textwidth(progressStatus.c_str()))/2), screenPos.Y + (Size.Y-8)/2, progressStatus, 255, 255, 255, 255);
+ else
+ g->drawtext(screenPos.X + ((Size.X-Graphics::textwidth(progressStatus.c_str()))/2), screenPos.Y + (Size.Y-8)/2, progressStatus, 0, 0, 0, 255);
+}
+
+void ProgressBar::Tick(float dt)
+{
+ intermediatePos += 1.0f*dt;
+ if(intermediatePos>100.0f)
+ intermediatePos = 0.0f;
+} \ No newline at end of file
diff --git a/src/gui/interface/ProgressBar.h b/src/gui/interface/ProgressBar.h
new file mode 100644
index 0000000..fc47f0c
--- /dev/null
+++ b/src/gui/interface/ProgressBar.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "Component.h"
+
+namespace ui
+{
+ class ProgressBar: public Component
+ {
+ int progress;
+ float intermediatePos;
+ std::string progressStatus;
+ public:
+ ProgressBar(Point position, Point size, int startProgress = 0, std::string startStatus = "");
+ virtual void SetProgress(int progress);
+ virtual int GetProgress();
+ virtual void SetStatus(std::string status);
+ virtual std::string GetStatus();
+ virtual void Draw(const Point & screenPos);
+ virtual void Tick(float dt);
+ };
+}
diff --git a/src/gui/interface/RichLabel.cpp b/src/gui/interface/RichLabel.cpp
new file mode 100644
index 0000000..f6143d3
--- /dev/null
+++ b/src/gui/interface/RichLabel.cpp
@@ -0,0 +1,198 @@
+#include <vector>
+#include <exception>
+
+#include "RichLabel.h"
+#include "Misc.h"
+#include "gui/interface/Point.h"
+#include "gui/interface/Component.h"
+#include "graphics/Graphics.h"
+
+using namespace ui;
+
+struct RichTextParseException: public std::exception {
+ std::string message;
+public:
+ RichTextParseException(std::string message_ = "Parse error"): message(message_) {}
+ const char * what() const throw()
+ {
+ return message.c_str();
+ }
+ ~RichTextParseException() throw() {};
+};
+
+RichLabel::RichLabel(Point position, Point size, std::string labelText):
+ Component(position, size),
+ textSource(labelText),
+ displayText("")
+{
+ updateRichText();
+}
+
+RichLabel::~RichLabel()
+{
+
+}
+
+void RichLabel::updateRichText()
+{
+ regions.clear();
+ displayText = "";
+
+ if(textSource.length())
+ {
+
+ enum State { ReadText, ReadData, ReadRegion, ReadDataStart };
+ State state = ReadText;
+
+ int currentDataPos = 0;
+ char * currentData = new char[textSource.length()+1];
+ std::fill(currentData, currentData+textSource.length()+1, 0);
+
+ int finalTextPos = 0;
+ char * finalText = new char[textSource.length()+1];
+ std::fill(finalText, finalText+textSource.length()+1, 0);
+
+ int originalTextPos = 0;
+ char * originalText = new char[textSource.length()+1];
+ std::copy(textSource.begin(), textSource.end(), originalText);
+ originalText[textSource.length()] = 0;
+
+ int stackPos = -1;
+ RichTextRegion * regionsStack = new RichTextRegion[256];
+
+ try
+ {
+ while(originalText[originalTextPos])
+ {
+ char current = originalText[originalTextPos];
+
+ if(state == ReadText)
+ {
+ if(current == '{')
+ {
+ if(stackPos > 255)
+ throw RichTextParseException("Too many nested regions");
+ stackPos++;
+ regionsStack[stackPos].start = finalTextPos;
+ regionsStack[stackPos].finish = finalTextPos;
+ state = ReadRegion;
+ }
+ else if(current == '}')
+ {
+ if(stackPos >= 0)
+ {
+ currentData[currentDataPos] = 0;
+ regionsStack[stackPos].actionData = std::string(currentData);
+ regions.push_back(regionsStack[stackPos]);
+ stackPos--;
+ }
+ else
+ {
+ throw RichTextParseException("Unexpected '}'");
+ }
+ }
+ else
+ {
+ finalText[finalTextPos++] = current;
+ finalText[finalTextPos] = 0;
+ if(stackPos >= 0)
+ {
+ regionsStack[stackPos].finish = finalTextPos;
+ }
+ }
+ }
+ else if(state == ReadData)
+ {
+ if(current == '|')
+ {
+ state = ReadText;
+ }
+ else
+ {
+ currentData[currentDataPos++] = current;
+ currentData[currentDataPos] = 0;
+ }
+ }
+ else if(state == ReadDataStart)
+ {
+ if(current != ':')
+ {
+ throw RichTextParseException("Expected ':'");
+ }
+ state = ReadData;
+ currentDataPos = 0;
+ }
+ else if(state == ReadRegion)
+ {
+ if(stackPos >= 0)
+ {
+ regionsStack[stackPos].action = current;
+ state = ReadDataStart;
+ }
+ else
+ {
+ throw RichTextParseException();
+ }
+ }
+
+ originalTextPos++;
+ }
+
+ if(stackPos != -1)
+ throw RichTextParseException("Unclosed region");
+
+ finalText[finalTextPos] = 0;
+ displayText = std::string(finalText);
+ }
+ catch (const RichTextParseException & e)
+ {
+ displayText = "\br[Parse exception: " + std::string(e.what()) + "]";
+ regions.clear();
+ }
+ delete[] currentData;
+ delete[] finalText;
+ delete[] originalText;
+ delete[] regionsStack;
+ }
+ TextPosition(displayText);
+}
+
+void RichLabel::SetText(std::string text)
+{
+ textSource = text;
+ updateRichText();
+}
+
+std::string RichLabel::GetDisplayText()
+{
+ return displayText;
+}
+
+std::string RichLabel::GetText()
+{
+ return textSource;
+}
+
+void RichLabel::Draw(const Point& screenPos)
+{
+ Graphics * g = ui::Engine::Ref().g;
+ ui::Colour textColour = Appearance.TextInactive;
+ g->drawtext(screenPos.X+textPosition.X, screenPos.Y+textPosition.Y, displayText, textColour.Red, textColour.Green, textColour.Blue, 255);
+}
+
+void RichLabel::OnMouseClick(int x, int y, unsigned button)
+{
+ int cursorPosition = Graphics::CharIndexAtPosition((char*)displayText.c_str(), x-textPosition.X, y-textPosition.Y);
+ for(std::vector<RichTextRegion>::iterator iter = regions.begin(), end = regions.end(); iter != end; ++iter)
+ {
+ if((*iter).start <= cursorPosition && (*iter).finish >= cursorPosition)
+ {
+ switch((*iter).action)
+ {
+ case 'a':
+ OpenURI((*iter).actionData);
+ break;
+ }
+ }
+ }
+}
diff --git a/src/gui/interface/RichLabel.h b/src/gui/interface/RichLabel.h
new file mode 100644
index 0000000..d9682f2
--- /dev/null
+++ b/src/gui/interface/RichLabel.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <string>
+
+#include "Component.h"
+#include "Colour.h"
+
+namespace ui
+{
+ class RichLabel : public Component
+ {
+ public:
+ struct RichTextRegion
+ {
+ int start;
+ int finish;
+ int action;
+ std::string actionData;
+ };
+
+ RichLabel(Point position, Point size, std::string richText);
+
+ virtual ~RichLabel();
+
+ virtual void SetText(std::string text);
+ virtual std::string GetDisplayText();
+ virtual std::string GetText();
+
+ virtual void Draw(const Point& screenPos);
+ virtual void OnMouseClick(int x, int y, unsigned button);
+ protected:
+ std::string textSource;
+ std::string displayText;
+
+ std::vector<RichTextRegion> regions;
+
+ void updateRichText();
+ };
+}
diff --git a/src/gui/interface/SaveButton.cpp b/src/gui/interface/SaveButton.cpp
new file mode 100644
index 0000000..9b2950f
--- /dev/null
+++ b/src/gui/interface/SaveButton.cpp
@@ -0,0 +1,430 @@
+#include <iostream>
+#include <typeinfo>
+
+#include "SaveButton.h"
+#include "client/SaveInfo.h"
+#include "graphics/Graphics.h"
+#include "Engine.h"
+#include "client/requestbroker/RequestBroker.h"
+#include "simulation/SaveRenderer.h"
+#include "Format.h"
+#include "ContextMenu.h"
+#include "Keys.h"
+
+namespace ui {
+
+SaveButton::SaveButton(Point position, Point size, SaveInfo * save):
+ Component(position, size),
+ file(NULL),
+ save(save),
+ thumbnail(NULL),
+ isMouseInside(false),
+ isButtonDown(false),
+ actionCallback(NULL),
+ selectable(false),
+ selected(false),
+ waitingForThumb(false),
+ isMouseInsideAuthor(false),
+ isMouseInsideHistory(false),
+ showVotes(false)
+{
+ if(save)
+ {
+ name = save->name;
+ if(Graphics::textwidth((char *)name.c_str()) > Size.X)
+ {
+ int position = Graphics::textwidthx((char *)name.c_str(), Size.X - 22);
+ name = name.erase(position, name.length()-position);
+ name += "...";
+ }
+
+ std::string votes, icon;
+
+ votes = format::NumberToString<int>(save->GetVotesUp()-save->GetVotesDown());
+ icon += 0xBB;
+ for (int j = 1; j < votes.length(); j++)
+ icon += 0xBC;
+ icon += 0xB9;
+ icon += 0xBA;
+
+ votesBackground = icon;
+
+ for (std::string::iterator iter = icon.begin(), end = icon.end(); iter != end; ++iter)
+ *iter -= 14;
+
+ votesBackground2 = icon;
+
+ for (std::string::iterator iter = votes.begin(), end = votes.end(); iter != end; ++iter)
+ if(*iter != '-')
+ *iter += 127;
+
+ votesString = votes;
+
+ int voteMax = std::max(save->GetVotesUp(),save->GetVotesDown());
+ if (voteMax)
+ {
+ if (voteMax < 34)
+ {
+ float ry = 33.0f/voteMax;
+ if (voteMax<8)
+ ry = ry/(8-voteMax);
+ voteBarHeightUp = (int)(save->GetVotesUp()*ry)-1;
+ voteBarHeightDown = (int)(save->GetVotesDown()*ry)-1;
+ }
+ else
+ {
+ float ry = voteMax/33.0f;
+ voteBarHeightUp = (int)(save->GetVotesUp()/ry)-1;
+ voteBarHeightDown = (int)(save->GetVotesDown()/ry)-1;
+ }
+ }
+ else
+ {
+ voteBarHeightUp = 0;
+ voteBarHeightDown = 0;
+ }
+ }
+}
+
+SaveButton::SaveButton(Point position, Point size, SaveFile * file):
+ Component(position, size),
+ save(NULL),
+ file(file),
+ thumbnail(NULL),
+ isMouseInside(false),
+ isButtonDown(false),
+ actionCallback(NULL),
+ selectable(false),
+ selected(false),
+ wantsDraw(false),
+ waitingForThumb(false),
+ isMouseInsideAuthor(false),
+ isMouseInsideHistory(false),
+ showVotes(false)
+{
+ if(file)
+ {
+ name = file->GetDisplayName();
+ if(Graphics::textwidth((char *)name.c_str()) > Size.X)
+ {
+ int position = Graphics::textwidthx((char *)name.c_str(), Size.X - 22);
+ name = name.erase(position, name.length()-position);
+ name += "...";
+ }
+ }
+}
+
+SaveButton::~SaveButton()
+{
+ RequestBroker::Ref().DetachRequestListener(this);
+
+ if(thumbnail)
+ delete thumbnail;
+ if(actionCallback)
+ delete actionCallback;
+ if(save)
+ delete save;
+ if(file)
+ delete file;
+}
+
+void SaveButton::OnResponseReady(void * imagePtr)
+{
+ VideoBuffer * image = (VideoBuffer*)imagePtr;
+ if(image)
+ {
+ if(thumbnail)
+ delete thumbnail;
+ thumbnail = image;
+ waitingForThumb = false;
+ }
+}
+
+void SaveButton::Tick(float dt)
+{
+ if(!thumbnail && !waitingForThumb)
+ {
+ float scaleFactor = (Size.Y-25)/((float)YRES);
+ ui::Point thumbBoxSize = ui::Point(((float)XRES)*scaleFactor, ((float)YRES)*scaleFactor);
+ if(save)
+ {
+ if(save->GetGameSave())
+ {
+ waitingForThumb = true;
+ RequestBroker::Ref().RenderThumbnail(save->GetGameSave(), thumbBoxSize.X, thumbBoxSize.Y, this);
+ }
+ else if(save->GetID())
+ {
+ waitingForThumb = true;
+ RequestBroker::Ref().RetrieveThumbnail(save->GetID(), save->GetVersion(), thumbBoxSize.X, thumbBoxSize.Y, this);
+ }
+ }
+ else if(file && file->GetGameSave())
+ {
+ waitingForThumb = true;
+ RequestBroker::Ref().RenderThumbnail(file->GetGameSave(), thumbBoxSize.X, thumbBoxSize.Y, this);
+ }
+ }
+}
+
+void SaveButton::Draw(const Point& screenPos)
+{
+ Graphics * g = ui::Engine::Ref().g;
+ float scaleFactor;
+ ui::Point thumbBoxSize(0, 0);
+
+ wantsDraw = true;
+
+ if(selected && selectable)
+ {
+ g->fillrect(screenPos.X, screenPos.Y, Size.X, Size.Y, 100, 170, 255, 100);
+ }
+
+ if(thumbnail)
+ {
+ thumbBoxSize = ui::Point(thumbnail->Width, thumbnail->Height);
+ if(save && save->id)
+ g->draw_image(thumbnail, screenPos.X-3+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, 255);
+ else
+ g->draw_image(thumbnail, screenPos.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, 255);
+ }
+ else
+ {
+ scaleFactor = (Size.Y-25)/((float)YRES);
+ thumbBoxSize = ui::Point(((float)XRES)*scaleFactor, ((float)YRES)*scaleFactor);
+ }
+ if(save)
+ {
+ if(save->id)
+ {
+ if(isMouseInside)
+ {
+ g->drawrect(screenPos.X-3+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, thumbBoxSize.X, thumbBoxSize.Y, 210, 230, 255, 255);
+ g->drawrect(screenPos.X-4+thumbBoxSize.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, 7, thumbBoxSize.Y, 210, 230, 255, 255);
+ }
+ else
+ {
+ g->drawrect(screenPos.X-3+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, thumbBoxSize.X, thumbBoxSize.Y, 180, 180, 180, 255);
+ g->drawrect(screenPos.X-4+thumbBoxSize.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, 7, thumbBoxSize.Y, 180, 180, 180, 255);
+ }
+
+ g->fillrect(screenPos.X-3+thumbBoxSize.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+1+(Size.Y-20-thumbBoxSize.Y)/2, 5, (thumbBoxSize.Y+1)/2-1, 0, 107, 10, 255);
+ g->fillrect(screenPos.X-3+thumbBoxSize.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-20)/2, 5, thumbBoxSize.Y/2-1, 107, 10, 0, 255);
+
+ g->fillrect(screenPos.X-2+thumbBoxSize.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-20)/2-voteBarHeightUp, 3, voteBarHeightUp, 57, 187, 57, 255); //green
+ g->fillrect(screenPos.X-2+thumbBoxSize.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-20)/2, 3, voteBarHeightDown, 187, 57, 57, 255); //red
+ }
+ else
+ {
+ if(isMouseInside)
+ g->drawrect(screenPos.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, thumbBoxSize.X, thumbBoxSize.Y, 210, 230, 255, 255);
+ else
+ g->drawrect(screenPos.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, thumbBoxSize.X, thumbBoxSize.Y, 180, 180, 180, 255);
+ }
+
+ if(isMouseInside && !isMouseInsideAuthor)
+ g->drawtext(screenPos.X+(Size.X-Graphics::textwidth((char *)name.c_str()))/2, screenPos.Y+Size.Y - 21, name, 255, 255, 255, 255);
+ else
+ g->drawtext(screenPos.X+(Size.X-Graphics::textwidth((char *)name.c_str()))/2, screenPos.Y+Size.Y - 21, name, 180, 180, 180, 255);
+
+ if(isMouseInsideAuthor)
+ g->drawtext(screenPos.X+(Size.X-Graphics::textwidth((char *)save->userName.c_str()))/2, screenPos.Y+Size.Y - 10, save->userName, 200, 230, 255, 255);
+ else
+ g->drawtext(screenPos.X+(Size.X-Graphics::textwidth((char *)save->userName.c_str()))/2, screenPos.Y+Size.Y - 10, save->userName, 100, 130, 160, 255);
+ if (showVotes)// && !isMouseInside)
+ {
+ int x = screenPos.X-7+(Size.X-thumbBoxSize.X)/2+thumbBoxSize.X-Graphics::textwidth(votesBackground.c_str());
+ int y = screenPos.Y-23+(Size.Y-thumbBoxSize.Y)/2+thumbBoxSize.Y;
+ g->drawtext(x, y, votesBackground, 16, 72, 16, 255);
+ g->drawtext(x, y, votesBackground2, 192, 192, 192, 255);
+ g->drawtext(x+3, y, votesString, 255, 255, 255, 255);
+ }
+ if (isMouseInsideHistory && showVotes)
+ {
+ int x = screenPos.X;
+ int y = screenPos.Y-15+(Size.Y-thumbBoxSize.Y)/2+thumbBoxSize.Y;
+ g->fillrect(x+1, y+1, 7, 8, 255, 255, 255, 255);
+ if (isMouseInsideHistory) {
+ g->drawtext(x, y, "\xA6", 200, 100, 80, 255);
+ } else {
+ g->drawtext(x, y, "\xA6", 160, 70, 50, 255);
+ }
+ }
+ if (!save->GetPublished())
+ {
+ g->drawtext(screenPos.X, screenPos.Y-2, "\xCD", 255, 255, 255, 255);
+ g->drawtext(screenPos.X, screenPos.Y-2, "\xCE", 212, 151, 81, 255);
+ }
+ }
+ if(file)
+ {
+ if(isMouseInside)
+ g->drawrect(screenPos.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, thumbBoxSize.X, thumbBoxSize.Y, 210, 230, 255, 255);
+ else
+ g->drawrect(screenPos.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, thumbBoxSize.X, thumbBoxSize.Y, 180, 180, 180, 255);
+
+ if(isMouseInside)
+ {
+ g->drawtext(screenPos.X+(Size.X-Graphics::textwidth((char *)name.c_str()))/2, screenPos.Y+Size.Y - 21, name, 255, 255, 255, 255);
+ }
+ else
+ {
+ g->drawtext(screenPos.X+(Size.X-Graphics::textwidth((char *)name.c_str()))/2, screenPos.Y+Size.Y - 21, name, 180, 180, 180, 255);
+ }
+ }
+
+ if(isMouseInside && selectable)
+ {
+ g->clearrect(screenPos.X+(Size.X-20), screenPos.Y+6, 14, 14);
+ g->drawrect(screenPos.X+(Size.X-20), screenPos.Y+6, 14, 14, 255, 255, 255, 255);
+ if(selected)
+ g->fillrect(screenPos.X+(Size.X-18), screenPos.Y+8, 10, 10, 255, 255, 255, 255);
+ }
+}
+
+void SaveButton::OnMouseUnclick(int x, int y, unsigned int button)
+{
+ if(button != 1)
+ {
+ return; //left click only!
+ }
+
+ if(x>=Size.X-20 && y>=6 && y<=20 && x<=Size.X-6 && selectable)
+ {
+ selected = !selected;
+ DoSelection();
+ return;
+ }
+
+ if(isButtonDown)
+ {
+ isButtonDown = false;
+ if(isMouseInsideHistory)
+ DoAltAction();
+ else if(isMouseInsideAuthor)
+ DoAltAction2();
+ else
+ DoAction();
+ }
+}
+
+void SaveButton::AddContextMenu(int menuType)
+{
+ if (menuType == 0) //Save browser
+ {
+ menu = new ContextMenu(this);
+ menu->AddItem(ContextMenuItem("Open", 0, true));
+ menu->AddItem(ContextMenuItem("Select", 1, true));
+ menu->AddItem(ContextMenuItem("View History", 2, true));
+ menu->AddItem(ContextMenuItem("More by this user", 3, true));
+ }
+ else if (menuType == 1) //Local save browser
+ {
+ menu = new ContextMenu(this);
+ menu->AddItem(ContextMenuItem("Open", 0, true));
+ menu->AddItem(ContextMenuItem("Rename", 2, true));
+ menu->AddItem(ContextMenuItem("Delete", 3, true));
+ }
+}
+
+void SaveButton::OnContextMenuAction(int item)
+{
+ switch(item)
+ {
+ case 0:
+ DoAction();
+ break;
+ case 1:
+ selected = !selected;
+ DoSelection();
+ break;
+ case 2:
+ DoAltAction();
+ break;
+ case 3:
+ DoAltAction2();
+ break;
+ }
+}
+
+void SaveButton::OnMouseClick(int x, int y, unsigned int button)
+{
+ if(button == BUTTON_RIGHT)
+ {
+ if(menu)
+ menu->Show(GetScreenPos() + ui::Point(x, y));
+ }
+ else
+ {
+ isButtonDown = true;
+ if(button !=1 && selectable)
+ {
+ selected = !selected;
+ DoSelection();
+ }
+
+ }
+}
+
+void SaveButton::OnMouseMovedInside(int x, int y, int dx, int dy)
+{
+ if(y > Size.Y-11)
+ isMouseInsideAuthor = true;
+ else
+ isMouseInsideAuthor = false;
+
+ if(showVotes && y > Size.Y-29 && y < Size.Y - 18 && x > 0 && x < 9)
+ isMouseInsideHistory = true;
+ else
+ isMouseInsideHistory = false;
+}
+
+void SaveButton::OnMouseEnter(int x, int y)
+{
+ isMouseInside = true;
+}
+
+void SaveButton::OnMouseLeave(int x, int y)
+{
+ isMouseInside = false;
+ isMouseInsideAuthor = false;
+ isMouseInsideHistory = false;
+}
+
+void SaveButton::DoAltAction()
+{
+ if(actionCallback)
+ actionCallback->AltActionCallback(this);
+}
+
+void SaveButton::DoAltAction2()
+{
+ if(actionCallback)
+ actionCallback->AltActionCallback2(this);
+}
+
+void SaveButton::DoAction()
+{
+ if(actionCallback)
+ actionCallback->ActionCallback(this);
+}
+
+void SaveButton::DoSelection()
+{
+ if(menu)
+ {
+ if(selected)
+ menu->SetItem(1, "Deselect");
+ else
+ menu->SetItem(1, "Select");
+ }
+ if(selectable && actionCallback)
+ actionCallback->SelectedCallback(this);
+}
+
+void SaveButton::SetActionCallback(SaveButtonAction * action)
+{
+ actionCallback = action;
+}
+
+} /* namespace ui */
diff --git a/src/gui/interface/SaveButton.h b/src/gui/interface/SaveButton.h
new file mode 100644
index 0000000..7bb77c4
--- /dev/null
+++ b/src/gui/interface/SaveButton.h
@@ -0,0 +1,83 @@
+#ifndef SAVEBUTTON_H_
+#define SAVEBUTTON_H_
+
+#include <string>
+
+#include "Component.h"
+#include "client/SaveFile.h"
+#include "client/SaveInfo.h"
+#include "client/requestbroker/RequestListener.h"
+#include "graphics/Graphics.h"
+#include "gui/interface/Colour.h"
+
+namespace ui
+{
+class SaveButton;
+class SaveButtonAction
+{
+public:
+ virtual void ActionCallback(ui::SaveButton * sender) {}
+ virtual void AltActionCallback(ui::SaveButton * sender) {}
+ virtual void AltActionCallback2(ui::SaveButton * sender) {}
+ virtual void SelectedCallback(ui::SaveButton * sender) {}
+ virtual ~SaveButtonAction() {}
+};
+
+class SaveButton : public Component, public RequestListener
+{
+ SaveFile * file;
+ SaveInfo * save;
+ VideoBuffer * thumbnail;
+ std::string name;
+ std::string votesString;
+ std::string votesBackground;
+ std::string votesBackground2;
+ int voteBarHeightUp;
+ int voteBarHeightDown;
+ bool wantsDraw;
+ bool waitingForThumb;
+ bool isMouseInsideAuthor;
+ bool isMouseInsideHistory;
+ bool showVotes;
+public:
+ SaveButton(Point position, Point size, SaveInfo * save);
+ SaveButton(Point position, Point size, SaveFile * file);
+ virtual ~SaveButton();
+
+ virtual void OnMouseClick(int x, int y, unsigned int button);
+ virtual void OnMouseUnclick(int x, int y, unsigned int button);
+
+ virtual void OnMouseEnter(int x, int y);
+ virtual void OnMouseLeave(int x, int y);
+
+ virtual void OnMouseMovedInside(int x, int y, int dx, int dy);
+
+ void AddContextMenu(int menuType);
+ virtual void OnContextMenuAction(int item);
+
+ virtual void Draw(const Point& screenPos);
+ virtual void Tick(float dt);
+
+ virtual void OnResponseReady(void * imagePtr);
+
+ void SetSelected(bool selected_) { selected = selected_; }
+ bool GetSelected() { return selected; }
+ void SetSelectable(bool selectable_) { selectable = selectable_; }
+ bool GetSelectable() { return selectable; }
+ void SetShowVotes(bool showVotes_) { showVotes = showVotes_; }
+
+ SaveInfo * GetSave() { return save; }
+ SaveFile * GetSaveFile() { return file; }
+ inline bool GetState() { return state; }
+ virtual void DoAction();
+ virtual void DoAltAction();
+ virtual void DoAltAction2();
+ virtual void DoSelection();
+ void SetActionCallback(SaveButtonAction * action);
+protected:
+ bool isButtonDown, state, isMouseInside, selected, selectable;
+ SaveButtonAction * actionCallback;
+};
+}
+#endif /* BUTTON_H_ */
+
diff --git a/src/gui/interface/ScrollPanel.cpp b/src/gui/interface/ScrollPanel.cpp
new file mode 100644
index 0000000..74f6b62
--- /dev/null
+++ b/src/gui/interface/ScrollPanel.cpp
@@ -0,0 +1,173 @@
+#include <iostream>
+#include "ScrollPanel.h"
+
+using namespace ui;
+
+ScrollPanel::ScrollPanel(Point position, Point size):
+ Panel(position, size),
+ maxOffset(0, 0),
+ offsetX(0),
+ offsetY(0),
+ yScrollVel(0.0f),
+ xScrollVel(0.0f),
+ scrollBarWidth(0),
+ isMouseInsideScrollbar(false),
+ scrollbarSelected(false),
+ scrollbarInitialYOffset(0),
+ scrollbarInitialYClick(0)
+{
+
+}
+
+int ScrollPanel::GetScrollLimit()
+{
+ if(ViewportPosition.Y == 0)
+ return -1;
+ else if(maxOffset.Y == -ViewportPosition.Y)
+ return 1;
+ return 0;
+}
+
+void ScrollPanel::XOnMouseWheelInside(int localx, int localy, int d)
+{
+ if(!d)
+ return;
+ yScrollVel -= d*2;
+}
+
+void ScrollPanel::Draw(const Point& screenPos)
+{
+ Panel::Draw(screenPos);
+
+ Graphics * g = ui::Engine::Ref().g;
+
+ //Vertical scroll bar
+ if(maxOffset.Y>0 && InnerSize.Y>0)
+ {
+ float scrollHeight = float(Size.Y)*(float(Size.Y)/float(InnerSize.Y));
+ float scrollPos = 0;
+ if(-ViewportPosition.Y>0)
+ {
+ scrollPos = float(Size.Y-scrollHeight)*(float(offsetY)/float(maxOffset.Y));
+ }
+
+ g->fillrect(screenPos.X+(Size.X-scrollBarWidth), screenPos.Y, scrollBarWidth, Size.Y, 125, 125, 125, 100);
+ g->fillrect(screenPos.X+(Size.X-scrollBarWidth), screenPos.Y+scrollPos, scrollBarWidth, scrollHeight, 255, 255, 255, 255);
+ }
+}
+
+void ScrollPanel::XOnMouseClick(int x, int y, unsigned int button)
+{
+ if (isMouseInsideScrollbar)
+ {
+ scrollbarSelected = true;
+ scrollbarInitialYOffset = offsetY;
+ scrollbarInitialYClick = y;
+ }
+}
+
+void ScrollPanel::XOnMouseUp(int x, int y, unsigned int button)
+{
+ scrollbarSelected = false;
+}
+
+void ScrollPanel::XOnMouseMoved(int x, int y, int dx, int dy)
+{
+ if(maxOffset.Y>0 && InnerSize.Y>0)
+ {
+ float scrollHeight = float(Size.Y)*(float(Size.Y)/float(InnerSize.Y));
+ float scrollPos = 0;
+ if(-ViewportPosition.Y>0)
+ {
+ scrollPos = float(Size.Y-scrollHeight)*(float(offsetY)/float(maxOffset.Y));
+ }
+
+ if (scrollbarSelected)
+ {
+ if (x > 0)
+ {
+ int scrollY = float(y-scrollbarInitialYClick)/float(Size.Y)*float(InnerSize.Y)+scrollbarInitialYOffset;
+ ViewportPosition.Y = -scrollY;
+ offsetY = scrollY;
+ }
+ else
+ {
+ ViewportPosition.Y = -scrollbarInitialYOffset;
+ offsetY = scrollbarInitialYOffset;
+ }
+ }
+
+ if (x > (Size.X-scrollBarWidth) && x < (Size.X-scrollBarWidth)+scrollBarWidth && y > scrollPos && y < scrollPos+scrollHeight)
+ isMouseInsideScrollbar = true;
+ else
+ isMouseInsideScrollbar = false;
+ }
+}
+
+void ScrollPanel::XTick(float dt)
+{
+ //if(yScrollVel > 7.0f) yScrollVel = 7.0f;
+ //if(yScrollVel < -7.0f) yScrollVel = -7.0f;
+ if(yScrollVel > -0.5f && yScrollVel < 0.5)
+ yScrollVel = 0;
+
+ if(xScrollVel > 7.0f) xScrollVel = 7.0f;
+ if(xScrollVel < -7.0f) xScrollVel = -7.0f;
+ if(xScrollVel > -0.5f && xScrollVel < 0.5)
+ xScrollVel = 0;
+
+ maxOffset = InnerSize-Size;
+ maxOffset.Y = std::max(0, maxOffset.Y);
+ maxOffset.X = std::max(0, maxOffset.X);
+
+ int oldOffsetY = offsetY;
+ offsetY += yScrollVel;
+ int oldOffsetX = offsetX;
+ offsetX += xScrollVel;
+
+ yScrollVel*=0.98f;
+ xScrollVel*=0.98f;
+
+ if(oldOffsetY!=int(offsetY))
+ {
+ if(offsetY<0)
+ {
+ offsetY = 0;
+ yScrollVel = 0;
+ //commentsBegin = true;
+ //commentsEnd = false;
+ }
+ else if(offsetY>maxOffset.Y)
+ {
+ offsetY = maxOffset.Y;
+ yScrollVel = 0;
+ //commentsEnd = true;
+ //commentsBegin = false;
+ }
+ else
+ {
+ //commentsEnd = false;
+ //commentsBegin = false;
+ }
+ ViewportPosition.Y = -offsetY;
+ }
+ else
+ {
+ if(offsetY<0)
+ {
+ offsetY = 0;
+ yScrollVel = 0;
+ ViewportPosition.Y = -offsetY;
+ }
+ else if(offsetY>maxOffset.Y)
+ {
+ offsetY = maxOffset.Y;
+ ViewportPosition.Y = -offsetY;
+ }
+ }
+
+ if(mouseInside && scrollBarWidth < 6)
+ scrollBarWidth++;
+ else if(!mouseInside && scrollBarWidth > 0 && !scrollbarSelected)
+ scrollBarWidth--;
+} \ No newline at end of file
diff --git a/src/gui/interface/ScrollPanel.h b/src/gui/interface/ScrollPanel.h
new file mode 100644
index 0000000..c26c420
--- /dev/null
+++ b/src/gui/interface/ScrollPanel.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "Panel.h"
+
+namespace ui
+{
+ class ScrollPanel: public Panel
+ {
+ protected:
+ int scrollBarWidth;
+ Point maxOffset;
+ float offsetX;
+ float offsetY;
+ float yScrollVel;
+ float xScrollVel;
+ bool isMouseInsideScrollbar;
+ bool scrollbarSelected;
+ int scrollbarInitialYOffset;
+ int scrollbarInitialYClick;
+ public:
+ ScrollPanel(Point position, Point size);
+
+ int GetScrollLimit();
+
+ virtual void Draw(const Point& screenPos);
+ virtual void XTick(float dt);
+ virtual void XOnMouseWheelInside(int localx, int localy, int d);
+ virtual void XOnMouseClick(int localx, int localy, unsigned int button);
+ virtual void XOnMouseUp(int x, int y, unsigned int button);
+ virtual void XOnMouseMoved(int localx, int localy, int dx, int dy);
+ };
+} \ No newline at end of file
diff --git a/src/gui/interface/Slider.cpp b/src/gui/interface/Slider.cpp
new file mode 100644
index 0000000..3ada74f
--- /dev/null
+++ b/src/gui/interface/Slider.cpp
@@ -0,0 +1,141 @@
+#include <iostream>
+#include "Slider.h"
+#include "Colour.h"
+
+namespace ui {
+
+Slider::Slider(Point position, Point size, int steps):
+ Component(position, size),
+ sliderSteps(steps),
+ sliderPosition(0),
+ isMouseDown(false),
+ bgGradient(NULL),
+ col1(0, 0, 0, 0),
+ col2(0, 0, 0, 0)
+{
+
+}
+
+void Slider::updatePosition(int position)
+{
+ if(position < 3)
+ position = 3;
+ if(position > Size.X-3)
+ position = Size.X-3;
+
+ float fPosition = position-3;
+ float fSize = Size.X-6;
+ float fSteps = sliderSteps;
+
+ float fSliderPosition = (fPosition/fSize)*sliderSteps;//position;//((x-3)/(Size.X-6))*sliderSteps;
+
+ int newSliderPosition = fSliderPosition;
+
+ if(newSliderPosition == sliderPosition)
+ return;
+
+ sliderPosition = newSliderPosition;
+
+ if(actionCallback)
+ {
+ actionCallback->ValueChangedCallback(this);
+ }
+}
+
+void Slider::OnMouseMoved(int x, int y, int dx, int dy)
+{
+ if(isMouseDown)
+ {
+ updatePosition(x);
+ }
+}
+
+void Slider::OnMouseClick(int x, int y, unsigned button)
+{
+ isMouseDown = true;
+ updatePosition(x);
+}
+
+void Slider::OnMouseUp(int x, int y, unsigned button)
+{
+ if(isMouseDown)
+ {
+ isMouseDown = false;
+ }
+}
+
+
+void Slider::SetColour(Colour col1, Colour col2)
+{
+ pixel pix[2] = {PIXRGB(col1.Red, col1.Green, col1.Blue), PIXRGB(col2.Red, col2.Green, col2.Blue)};
+ float fl[2] = {0.0f, 1.0f};
+ if(bgGradient)
+ free(bgGradient);
+ this->col1 = col1;
+ this->col2 = col2;
+ bgGradient = (unsigned char*)Graphics::GenerateGradient(pix, fl, 2, Size.X-7);
+}
+
+int Slider::GetValue()
+{
+ return sliderPosition;
+}
+
+void Slider::SetValue(int value)
+{
+ if(value < 0)
+ value = 0;
+ if(value > sliderSteps)
+ value = sliderSteps;
+ sliderPosition = value;
+}
+
+int Slider::GetSteps()
+{
+ return sliderSteps;
+}
+
+void Slider::SetSteps(int steps)
+{
+ if(steps < 0)
+ steps = 0;
+ if(steps < sliderPosition)
+ sliderPosition = steps;
+ sliderSteps = steps;
+}
+
+void Slider::Draw(const Point& screenPos)
+{
+ Graphics * g = Engine::Ref().g;
+ //g->drawrect(screenPos.X, screenPos.Y, Size.X, Size.Y, 255, 255, 255, 255);
+
+ if(bgGradient)
+ {
+#ifndef OGLI
+ for (int j = 3; j < Size.Y-7; j++)
+ for (int i = 3; i < Size.X-7; i++)
+ g->blendpixel(screenPos.X+i+2, screenPos.Y+j+2, bgGradient[(i-3)*3], bgGradient[(i-3)*3+1], bgGradient[(i-3)*3+2], 255);
+#else
+ g->gradientrect(screenPos.X+5, screenPos.Y+5, Size.X-10, Size.Y-10, col1.Red, col1.Green, col1.Blue, col1.Alpha, col2.Red, col2.Green, col2.Blue, col2.Alpha);
+#endif
+ }
+
+ g->drawrect(screenPos.X+3, screenPos.Y+3, Size.X-6, Size.Y-6, 255, 255, 255, 255);
+
+ float fPosition = sliderPosition;
+ float fSize = Size.X-6;
+ float fSteps = sliderSteps;
+
+ float fSliderX = (fSize/fSteps)*fPosition;//sliderPosition;//((Size.X-6)/sliderSteps)*sliderPosition;
+ int sliderX = fSliderX;
+ sliderX += 3;
+
+ g->fillrect(screenPos.X+sliderX-2, screenPos.Y+1, 4, Size.Y-2, 20, 20, 20, 255);
+ g->drawrect(screenPos.X+sliderX-2, screenPos.Y+1, 4, Size.Y-2, 200, 200, 200, 255);
+}
+
+Slider::~Slider()
+{
+}
+
+} /* namespace ui */
diff --git a/src/gui/interface/Slider.h b/src/gui/interface/Slider.h
new file mode 100644
index 0000000..b02366e
--- /dev/null
+++ b/src/gui/interface/Slider.h
@@ -0,0 +1,40 @@
+#ifndef SLIDER_H_
+#define SLIDER_H_
+
+#include "Component.h"
+#include "Colour.h"
+
+namespace ui {
+class Slider;
+class SliderAction
+{
+public:
+ virtual void ValueChangedCallback(ui::Slider * sender) {}
+ virtual ~SliderAction() {}
+};
+class Slider: public ui::Component {
+ friend class SliderAction;
+ int sliderSteps;
+ int sliderPosition;
+ bool isMouseDown;
+ unsigned char * bgGradient;
+ SliderAction * actionCallback;
+ Colour col1, col2;
+ void updatePosition(int position);
+public:
+ Slider(Point position, Point size, int steps);
+ virtual void OnMouseMoved(int x, int y, int dx, int dy);
+ virtual void OnMouseClick(int x, int y, unsigned button);
+ virtual void OnMouseUp(int x, int y, unsigned button);
+ virtual void Draw(const Point& screenPos);
+ void SetColour(Colour col1, Colour col2);
+ void SetActionCallback(SliderAction * action) { actionCallback = action; }
+ int GetValue();
+ void SetValue(int value);
+ int GetSteps();
+ void SetSteps(int steps);
+ virtual ~Slider();
+};
+
+} /* namespace ui */
+#endif /* SLIDER_H_ */
diff --git a/src/gui/interface/Spinner.cpp b/src/gui/interface/Spinner.cpp
new file mode 100644
index 0000000..fd3a61d
--- /dev/null
+++ b/src/gui/interface/Spinner.cpp
@@ -0,0 +1,37 @@
+#include <cmath>
+#include <iostream>
+#include "Spinner.h"
+
+using namespace ui;
+
+Spinner::Spinner(Point position, Point size):
+ Component(position, size), cValue(0),
+ tickInternal(0)
+{
+}
+void Spinner::Tick(float dt)
+{
+ tickInternal++;
+ if(tickInternal == 4)
+ {
+ cValue += 0.25f;//0.05f;
+ tickInternal = 0;
+ }
+}
+void Spinner::Draw(const Point& screenPos)
+{
+ Graphics * g = ui::Engine::Ref().g;
+ int baseX = screenPos.X+(Size.X/2);
+ int baseY = screenPos.Y+(Size.Y/2);
+ int lineInner = (Size.X/2);
+ int lineOuter = (Size.X/2)+3;
+ for(float t = 0.0f; t < 6.0f; t+=0.25f)
+ {
+ //g->drawblob(baseX+(sin(cValue+t)*(Size.X/2)), baseY+(cos(cValue+t)*(Size.X/2)), t*255, t*255, t*255);
+ g->draw_line(baseX+(sin(cValue+t)*lineInner), baseY+(cos(cValue+t)*lineInner), baseX+(sin(cValue+t)*lineOuter), baseY+(cos(cValue+t)*lineOuter), (t/6)*255, (t/6)*255, (t/6)*255, 255);
+ }
+}
+Spinner::~Spinner()
+{
+
+}
diff --git a/src/gui/interface/Spinner.h b/src/gui/interface/Spinner.h
new file mode 100644
index 0000000..deabb3c
--- /dev/null
+++ b/src/gui/interface/Spinner.h
@@ -0,0 +1,23 @@
+#ifndef SPINNER_H_
+#define SPINNER_H_
+
+#include "Component.h"
+
+namespace ui
+{
+
+class Spinner: public Component
+{
+ float cValue;
+ int tickInternal;
+public:
+ Spinner(Point position, Point size);
+ virtual void Tick(float dt);
+ virtual void Draw(const Point& screenPos);
+ virtual ~Spinner();
+};
+
+}
+
+
+#endif /* SPINNER_H_ */
diff --git a/src/gui/interface/Textbox.cpp b/src/gui/interface/Textbox.cpp
new file mode 100644
index 0000000..c23bcb4
--- /dev/null
+++ b/src/gui/interface/Textbox.cpp
@@ -0,0 +1,707 @@
+#include <string>
+#include <iostream>
+#include <stdexcept>
+#include <time.h>
+#include "Config.h"
+#include "gui/interface/Point.h"
+#include "gui/interface/Textbox.h"
+#include "gui/interface/Keys.h"
+#include "ContextMenu.h"
+
+using namespace ui;
+
+Textbox::Textbox(Point position, Point size, std::string textboxText, std::string textboxPlaceholder):
+ Label(position, size, ""),
+ actionCallback(NULL),
+ masked(false),
+ border(true),
+ mouseDown(false),
+ limit(std::string::npos),
+ inputType(All),
+ keyDown(0),
+ characterDown(0),
+ ReadOnly(false)
+{
+ placeHolder = textboxPlaceholder;
+
+ SetText(textboxText);
+ cursor = text.length();
+
+ menu->RemoveItem(0);
+ menu->AddItem(ContextMenuItem("Cut", 1, true));
+ menu->AddItem(ContextMenuItem("Copy", 0, true));
+ menu->AddItem(ContextMenuItem("Paste", 2, true));
+}
+
+Textbox::~Textbox()
+{
+ if(actionCallback)
+ delete actionCallback;
+}
+
+void Textbox::SetHidden(bool hidden)
+{
+ menu->RemoveItem(0);
+ menu->RemoveItem(1);
+ menu->RemoveItem(2);
+ menu->AddItem(ContextMenuItem("Cut", 1, !hidden));
+ menu->AddItem(ContextMenuItem("Copy", 0, !hidden));
+ menu->AddItem(ContextMenuItem("Paste", 2, true));
+
+ masked = hidden;
+}
+
+void Textbox::SetPlaceholder(std::string text)
+{
+ placeHolder = text;
+}
+
+void Textbox::SetText(std::string newText)
+{
+ backingText = newText;
+
+ if(masked)
+ {
+ std::string maskedText = std::string(newText);
+ std::fill(maskedText.begin(), maskedText.end(), '\x8D');
+ Label::SetText(maskedText);
+ }
+ else
+ Label::SetText(newText);
+
+ cursor = newText.length();
+
+ if(cursor)
+ {
+ Graphics::PositionAtCharIndex(multiline?((char*)textLines.c_str()):((char*)text.c_str()), cursor, cursorPositionX, cursorPositionY);
+ }
+ else
+ {
+ cursorPositionY = cursorPositionX = 0;
+ }
+}
+
+Textbox::ValidInput Textbox::GetInputType()
+{
+ return inputType;
+}
+
+void Textbox::SetInputType(ValidInput input)
+{
+ inputType = input;
+}
+
+void Textbox::SetLimit(size_t limit)
+{
+ this->limit = limit;
+}
+
+size_t Textbox::GetLimit()
+{
+ return limit;
+}
+
+std::string Textbox::GetText()
+{
+ return backingText;
+}
+
+void Textbox::OnContextMenuAction(int item)
+{
+ switch(item)
+ {
+ case 0:
+ copySelection();
+ break;
+ case 1:
+ cutSelection();
+ break;
+ case 2:
+ pasteIntoSelection();
+ break;
+ }
+}
+
+void Textbox::cutSelection()
+{
+ char * clipboardText;
+ clipboardText = ClipboardPull();
+ std::string newText = std::string(clipboardText);
+ free(clipboardText);
+ if(HasSelection())
+ {
+ if(getLowerSelectionBound() < 0 || getHigherSelectionBound() > backingText.length())
+ return;
+ ClipboardPush((char*)backingText.substr(getLowerSelectionBound(), getHigherSelectionBound()-getLowerSelectionBound()).c_str());
+ backingText.erase(backingText.begin()+getLowerSelectionBound(), backingText.begin()+getHigherSelectionBound());
+ cursor = getLowerSelectionBound();
+ }
+ else
+ {
+ ClipboardPush((char*)backingText.c_str());
+ backingText.clear();
+ }
+ ClearSelection();
+
+ if(masked)
+ {
+ std::string maskedText = std::string(backingText);
+ std::fill(maskedText.begin(), maskedText.end(), '\x8D');
+ Label::SetText(maskedText);
+ }
+ else
+ {
+ text = backingText;
+ }
+ if(actionCallback)
+ actionCallback->TextChangedCallback(this);
+
+ if(multiline)
+ updateMultiline();
+ updateSelection();
+ TextPosition(text);
+
+ if(cursor)
+ {
+ Graphics::PositionAtCharIndex(multiline?((char*)textLines.c_str()):((char*)text.c_str()), cursor, cursorPositionX, cursorPositionY);
+ }
+ else
+ {
+ cursorPositionY = cursorPositionX = 0;
+ }
+}
+
+void Textbox::selectAll()
+{
+ selectionIndex0 = 0;
+ selectionIndex1 = text.length();
+ updateSelection();
+}
+
+void Textbox::pasteIntoSelection()
+{
+ char * clipboardText;
+ clipboardText = ClipboardPull();
+ std::string newText = std::string(clipboardText);
+ free(clipboardText);
+ if(HasSelection())
+ {
+ if(getLowerSelectionBound() < 0 || getHigherSelectionBound() > backingText.length())
+ return;
+ backingText.erase(backingText.begin()+getLowerSelectionBound(), backingText.begin()+getHigherSelectionBound());
+ cursor = getLowerSelectionBound();
+ }
+ for(std::string::iterator iter = newText.begin(), end = newText.end(); iter != end; ++iter)
+ {
+ if(!CharacterValid(*iter))
+ {
+ if(inputType == All)
+ {
+ if(*iter == '\n' || *iter == '\r')
+ *iter = ' ';
+ else
+ *iter = '?';
+ }
+ else
+ *iter = '0';
+ }
+ }
+
+ int regionWidth = Size.X;
+ if(Appearance.icon)
+ regionWidth -= 13;
+ regionWidth -= Appearance.Margin.Left;
+ regionWidth -= Appearance.Margin.Right;
+
+ if(limit!=std::string::npos)
+ {
+ if(limit-backingText.length() >= 0)
+ newText = newText.substr(0, limit-backingText.length());
+ else
+ newText = "";
+ }
+ else if(!multiline && Graphics::textwidth((char*)std::string(backingText+newText).c_str()) > regionWidth)
+ {
+ int pLimit = regionWidth - Graphics::textwidth((char*)backingText.c_str());
+ int cIndex = Graphics::CharIndexAtPosition((char *)newText.c_str(), pLimit, 0);
+
+ if(cIndex > 0)
+ newText = newText.substr(0, cIndex);
+ else
+ newText = "";
+ }
+
+ backingText.insert(cursor, newText);
+ cursor = cursor+newText.length();
+ ClearSelection();
+
+ if(masked)
+ {
+ std::string maskedText = std::string(backingText);
+ std::fill(maskedText.begin(), maskedText.end(), '\x8D');
+ Label::SetText(maskedText);
+ }
+ else
+ {
+ text = backingText;
+ }
+ if(actionCallback)
+ actionCallback->TextChangedCallback(this);
+
+ if(multiline)
+ updateMultiline();
+ updateSelection();
+ if(multiline)
+ TextPosition(textLines);
+ else
+ TextPosition(text);
+
+ if(cursor)
+ {
+ Graphics::PositionAtCharIndex(multiline?((char*)textLines.c_str()):((char*)text.c_str()), cursor, cursorPositionX, cursorPositionY);
+ }
+ else
+ {
+ cursorPositionY = cursorPositionX = 0;
+ }
+}
+
+bool Textbox::CharacterValid(Uint16 character)
+{
+ switch(inputType)
+ {
+ case Number:
+ case Numeric:
+ return (character >= '0' && character <= '9');
+ case All:
+ default:
+ return (character >= ' ' && character < 127);
+ }
+ return false;
+}
+
+void Textbox::Tick(float dt)
+{
+ Label::Tick(dt);
+ if(!IsFocused())
+ {
+ keyDown = 0;
+ characterDown = 0;
+ }
+ if((keyDown || characterDown) && repeatTime <= clock())
+ {
+ OnVKeyPress(keyDown, characterDown, false, false, false);
+ repeatTime = clock()+(0.03 * CLOCKS_PER_SEC);
+ }
+}
+
+void Textbox::OnKeyRelease(int key, Uint16 character, bool shift, bool ctrl, bool alt)
+{
+ keyDown = 0;
+ characterDown = 0;
+}
+
+void Textbox::OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt)
+{
+ characterDown = character;
+ keyDown = key;
+ repeatTime = clock()+(0.3 * CLOCKS_PER_SEC);
+ OnVKeyPress(key, character, shift, ctrl, alt);
+}
+
+void Textbox::OnVKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt)
+{
+ bool changed = false;
+ if(ctrl && key == 'c' && !masked)
+ {
+ copySelection();
+ return;
+ }
+ if(ctrl && key == 'v' && !ReadOnly)
+ {
+ pasteIntoSelection();
+ return;
+ }
+ if(ctrl && key == 'x' && !masked && !ReadOnly)
+ {
+ cutSelection();
+ return;
+ }
+ if(ctrl && key == 'a')
+ {
+ selectAll();
+ return;
+ }
+
+ try
+ {
+ switch(key)
+ {
+ case KEY_HOME:
+ cursor = 0;
+ ClearSelection();
+ break;
+ case KEY_END:
+ cursor = backingText.length();
+ ClearSelection();
+ break;
+ case KEY_LEFT:
+ if(cursor > 0)
+ cursor--;
+ ClearSelection();
+ break;
+ case KEY_RIGHT:
+ if(cursor < backingText.length())
+ cursor++;
+ ClearSelection();
+ break;
+ case KEY_DELETE:
+ if(ReadOnly)
+ break;
+ if(HasSelection())
+ {
+ if(getLowerSelectionBound() < 0 || getHigherSelectionBound() > backingText.length())
+ return;
+ backingText.erase(backingText.begin()+getLowerSelectionBound(), backingText.begin()+getHigherSelectionBound());
+ cursor = getLowerSelectionBound();
+ changed = true;
+ }
+ else if(backingText.length() && cursor < backingText.length())
+ {
+ if(ctrl)
+ backingText.erase(cursor, backingText.length()-cursor);
+ else
+ backingText.erase(cursor, 1);
+ changed = true;
+ }
+ ClearSelection();
+ break;
+ case KEY_BACKSPACE:
+ if(ReadOnly)
+ break;
+ if(HasSelection())
+ {
+ if(getLowerSelectionBound() < 0 || getHigherSelectionBound() > backingText.length())
+ return;
+ backingText.erase(backingText.begin()+getLowerSelectionBound(), backingText.begin()+getHigherSelectionBound());
+ cursor = getLowerSelectionBound();
+ changed = true;
+ }
+ else if(backingText.length() && cursor > 0)
+ {
+ if(ctrl)
+ {
+ backingText.erase(0, cursor);
+ cursor = 0;
+ }
+ else
+ {
+ backingText.erase(cursor-1, 1);
+ cursor--;
+ }
+ changed = true;
+ }
+ ClearSelection();
+ break;
+ }
+ if(CharacterValid(character) && !ReadOnly)
+ {
+ if(HasSelection())
+ {
+ if(getLowerSelectionBound() < 0 || getHigherSelectionBound() > backingText.length())
+ return;
+ backingText.erase(backingText.begin()+getLowerSelectionBound(), backingText.begin()+getHigherSelectionBound());
+ cursor = getLowerSelectionBound();
+ }
+
+ int regionWidth = Size.X;
+ if(Appearance.icon)
+ regionWidth -= 13;
+ regionWidth -= Appearance.Margin.Left;
+ regionWidth -= Appearance.Margin.Right;
+ if((limit==std::string::npos || backingText.length() < limit) && (Graphics::textwidth((char*)std::string(backingText+char(character)).c_str()) <= regionWidth || multiline || limit!=std::string::npos))
+ {
+ if(cursor == backingText.length())
+ {
+ backingText += character;
+ }
+ else
+ {
+ backingText.insert(cursor, 1, (char)character);
+ }
+ cursor++;
+ }
+ changed = true;
+ ClearSelection();
+ }
+ }
+ catch(std::out_of_range &e)
+ {
+ cursor = 0;
+ backingText = "";
+ }
+ if(inputType == Number)
+ {
+ //Remove extra preceding 0's
+ while(backingText[0] == '0' && backingText.length()>1)
+ backingText.erase(backingText.begin());
+ }
+ if(cursor > backingText.length())
+ cursor = backingText.length();
+ if(changed)
+ {
+ if(masked)
+ {
+ std::string maskedText = std::string(backingText);
+ std::fill(maskedText.begin(), maskedText.end(), '\x8D');
+ Label::SetText(maskedText);
+ }
+ else
+ {
+ text = backingText;
+ }
+ if(actionCallback)
+ actionCallback->TextChangedCallback(this);
+ }
+
+ if(multiline)
+ updateMultiline();
+ updateSelection();
+ if(multiline)
+ TextPosition(textLines);
+ else
+ TextPosition(text);
+
+ if(cursor)
+ {
+ Graphics::PositionAtCharIndex(multiline?((char*)textLines.c_str()):((char*)text.c_str()), cursor, cursorPositionX, cursorPositionY);
+ }
+ else
+ {
+ cursorPositionY = cursorPositionX = 0;
+ }
+}
+
+void Textbox::OnMouseClick(int x, int y, unsigned button)
+{
+
+ if(button != BUTTON_RIGHT)
+ {
+ mouseDown = true;
+ cursor = Graphics::CharIndexAtPosition(multiline?((char*)textLines.c_str()):((char*)text.c_str()), x-textPosition.X, y-textPosition.Y);
+ if(cursor)
+ {
+ Graphics::PositionAtCharIndex(multiline?((char*)textLines.c_str()):((char*)text.c_str()), cursor, cursorPositionX, cursorPositionY);
+ }
+ else
+ {
+ cursorPositionY = cursorPositionX = 0;
+ }
+ }
+ Label::OnMouseClick(x, y, button);
+}
+
+void Textbox::OnMouseUp(int x, int y, unsigned button)
+{
+ mouseDown = false;
+ Label::OnMouseUp(x, y, button);
+}
+
+void Textbox::OnMouseMoved(int localx, int localy, int dx, int dy)
+{
+ if(mouseDown)
+ {
+ cursor = Graphics::CharIndexAtPosition(multiline?((char*)textLines.c_str()):((char*)text.c_str()), localx-textPosition.X, localy-textPosition.Y);
+ if(cursor)
+ {
+ Graphics::PositionAtCharIndex(multiline?((char*)textLines.c_str()):((char*)text.c_str()), cursor, cursorPositionX, cursorPositionY);
+ }
+ else
+ {
+ cursorPositionY = cursorPositionX = 0;
+ }
+ }
+ Label::OnMouseMoved(localx, localy, dx, dy);
+}
+
+void Textbox::Draw(const Point& screenPos)
+{
+ Label::Draw(screenPos);
+
+ Graphics * g = Engine::Ref().g;
+ if(IsFocused())
+ {
+ if(border) g->drawrect(screenPos.X, screenPos.Y, Size.X, Size.Y, 255, 255, 255, 255);
+ g->draw_line(screenPos.X+textPosition.X+cursorPositionX, screenPos.Y-2+textPosition.Y+cursorPositionY, screenPos.X+textPosition.X+cursorPositionX, screenPos.Y+9+textPosition.Y+cursorPositionY, 255, 255, 255, 255);
+ }
+ else
+ {
+ if(!text.length())
+ {
+ g->drawtext(screenPos.X+textPosition.X, screenPos.Y+textPosition.Y, placeHolder, textColour.Red, textColour.Green, textColour.Blue, 170);
+ }
+ if(border) g->drawrect(screenPos.X, screenPos.Y, Size.X, Size.Y, 160, 160, 160, 255);
+ }
+ if(Appearance.icon)
+ g->draw_icon(screenPos.X+iconPosition.X, screenPos.Y+iconPosition.Y, Appearance.icon);
+}
+
+/*
+Textbox::Textbox(Point position, Point size, std::string textboxText):
+ Component(position, size),
+ text(textboxText),
+ actionCallback(NULL),
+ masked(false),
+ border(true)
+{
+ SetText(textboxText);
+ cursor = text.length();
+}
+
+Textbox::~Textbox()
+{
+ if(actionCallback)
+ delete actionCallback;
+}
+
+void Textbox::TextPosition()
+{
+ if(cursor)
+ {
+ cursorPosition = Graphics::textnwidth((char *)displayText.c_str(), cursor);
+ }
+ else
+ {
+ cursorPosition = 0;
+ }
+ Component::TextPosition(displayText);
+}
+
+void Textbox::SetText(std::string text)
+{
+ cursor = text.length();
+ this->text = text;
+ this->displayText = text;
+ TextPosition();
+}
+
+
+void Textbox::SetDisplayText(std::string text)
+{
+ displayText = text;
+ TextPosition();
+}
+
+std::string Textbox::GetText()
+{
+ return text;
+}
+
+void Textbox::OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt)
+{
+ bool changed = false;
+ try
+ {
+ switch(key)
+ {
+ case KEY_HOME:
+ cursor = 0;
+ break;
+ case KEY_END:
+ cursor = text.length();
+ break;
+ case KEY_LEFT:
+ if(cursor > 0)
+ cursor--;
+ break;
+ case KEY_RIGHT:
+ if(cursor < text.length())
+ cursor++;
+ break;
+ case KEY_DELETE:
+ if(text.length() && cursor < text.length())
+ {
+ if(ctrl)
+ text.erase(cursor, text.length()-cursor);
+ else
+ text.erase(cursor, 1);
+ changed = true;
+ }
+ break;
+ case KEY_BACKSPACE:
+ if(text.length() && cursor > 0)
+ {
+ if(ctrl)
+ {
+ text.erase(0, cursor);
+ cursor = 0;
+ }
+ else
+ {
+ text.erase(cursor-1, 1);
+ cursor--;
+ }
+ changed = true;
+ }
+ break;
+ }
+ if(character >= ' ' && character < 127)
+ {
+ if(cursor == text.length())
+ {
+ text += character;
+ }
+ else
+ {
+ text.insert(cursor, 1, (char)character);
+ }
+ cursor++;
+ changed = true;
+ }
+ }
+ catch(std::out_of_range &e)
+ {
+ cursor = 0;
+ text = "";
+ }
+ if(changed)
+ {
+ if(masked)
+ {
+ char * tempText = new char[text.length()+1];
+ std::fill(tempText, tempText+text.length(), 0x8d);
+ tempText[text.length()] = 0;
+ displayText = std::string(tempText);
+ delete tempText;
+ }
+ else
+ {
+ displayText = text;
+ }
+ if(actionCallback)
+ actionCallback->TextChangedCallback(this);
+ }
+ TextPosition();
+}
+
+void Textbox::Draw(const Point& screenPos)
+{
+ if(!drawn)
+ {
+ TextPosition();
+ drawn = true;
+ }
+ Graphics * g = Engine::Ref().g;
+ if(IsFocused())
+ {
+ if(border) g->drawrect(screenPos.X, screenPos.Y, Size.X, Size.Y, 255, 255, 255, 255);
+ g->draw_line(screenPos.X+textPosition.X+cursorPosition, screenPos.Y+3, screenPos.X+textPosition.X+cursorPosition, screenPos.Y+12, 255, 255, 255, XRES+BARSIZE);
+ }
+ else
+ {
+ if(border) g->drawrect(screenPos.X, screenPos.Y, Size.X, Size.Y, 160, 160, 160, 255);
+ }
+ g->drawtext(screenPos.X+textPosition.X, screenPos.Y+textPosition.Y, displayText, 255, 255, 255, 255);
+ if(Appearance.icon)
+ g->draw_icon(screenPos.X+iconPosition.X, screenPos.Y+iconPosition.Y, Appearance.icon);
+}*/
diff --git a/src/gui/interface/Textbox.h b/src/gui/interface/Textbox.h
new file mode 100644
index 0000000..0d5140b
--- /dev/null
+++ b/src/gui/interface/Textbox.h
@@ -0,0 +1,108 @@
+#ifndef TEXTBOX_H
+#define TEXTBOX_H
+
+#include <string>
+
+#include "Label.h"
+#include "PowderToy.h"
+
+namespace ui
+{
+class Textbox;
+class TextboxAction
+{
+public:
+ virtual void TextChangedCallback(ui::Textbox * sender) {}
+ virtual ~TextboxAction() {}
+};
+
+class Textbox : public Label
+{
+ friend class TextboxAction;
+public:
+ bool ReadOnly;
+ enum ValidInput { All, Numeric, Number };
+ Textbox(Point position, Point size, std::string textboxText = "", std::string textboxPlaceholder = "");
+ virtual ~Textbox();
+
+ virtual void SetText(std::string text);
+ virtual std::string GetText();
+
+ virtual void SetPlaceholder(std::string text);
+
+ void SetBorder(bool border) { this->border = border; };
+ void SetHidden(bool hidden);
+ bool GetHidden() { return masked; }
+ void SetActionCallback(TextboxAction * action) { actionCallback = action; }
+
+ void SetLimit(size_t limit);
+ size_t GetLimit();
+
+ ValidInput GetInputType();
+ void SetInputType(ValidInput input);
+
+ //Determines if the given character is valid given the input type
+ bool CharacterValid(Uint16 character);
+
+ virtual void Tick(float dt);
+ virtual void OnContextMenuAction(int item);
+ virtual void OnMouseClick(int x, int y, unsigned button);
+ virtual void OnMouseUp(int x, int y, unsigned button);
+ virtual void OnMouseMoved(int localx, int localy, int dx, int dy);
+ virtual void OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt);
+ virtual void OnVKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt);
+ virtual void OnKeyRelease(int key, Uint16 character, bool shift, bool ctrl, bool alt);
+ virtual void Draw(const Point& screenPos);
+
+protected:
+ ValidInput inputType;
+ size_t limit;
+ int repeatTime;
+ int keyDown;
+ Uint16 characterDown;
+ bool mouseDown;
+ bool masked, border;
+ int cursor, cursorPositionX, cursorPositionY;
+ TextboxAction *actionCallback;
+ std::string backingText;
+ std::string placeHolder;
+
+ virtual void selectAll();
+ virtual void cutSelection();
+ virtual void pasteIntoSelection();
+};
+
+/*class Textbox : public Component
+{
+ friend class TextboxAction;
+protected:
+ std::string text;
+ std::string displayText;
+ int cursor, cursorPosition;
+ TextboxAction *actionCallback;
+ bool masked;
+ bool border;
+public:
+ Textbox(Point position, Point size, std::string textboxText);
+ virtual ~Textbox();
+
+ virtual void SetText(std::string text);
+ virtual void SetDisplayText(std::string text);
+ std::string GetText();
+ void SetActionCallback(TextboxAction * action) { actionCallback = action; }
+ virtual void OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt);
+
+ void SetHidden(bool hidden) { masked = hidden; }
+ bool GetHidden() { return masked; }
+
+ void SetBorder(bool border) {this->border = border;}
+
+ void TextPosition();
+
+ virtual void Draw(const Point& screenPos);
+};
+}*/
+}
+
+
+#endif // TEXTBOX_H
diff --git a/src/gui/interface/Window.cpp b/src/gui/interface/Window.cpp
new file mode 100644
index 0000000..9ec6857
--- /dev/null
+++ b/src/gui/interface/Window.cpp
@@ -0,0 +1,558 @@
+#include <iostream>
+#include "Window.h"
+#include "Keys.h"
+#include "Component.h"
+#include "gui/interface/Point.h"
+#include "gui/interface/Button.h"
+
+using namespace ui;
+
+Window::Window(Point _position, Point _size):
+ Position(_position),
+ Size(_size),
+ focusedComponent_(NULL),
+ AllowExclusiveDrawing(true),
+ halt(false),
+ destruct(false),
+ stop(false),
+ cancelButton(NULL),
+ okayButton(NULL)
+#ifdef DEBUG
+ ,debugMode(false)
+#endif
+{
+}
+
+Window::~Window()
+{
+ for(unsigned i = 0, sz = Components.size(); i < sz; ++i)
+ if( Components[i] )
+ {
+ delete Components[i];
+ if(Components[i]==focusedComponent_)
+ focusedComponent_ = NULL;
+ }
+ Components.clear();
+}
+
+void Window::AddComponent(Component* c)
+{
+ // TODO: do a check if component was already added?
+ if(c->GetParentWindow()==NULL)
+ {
+ c->SetParentWindow(this);
+ Components.push_back(c);
+
+ if(Engine::Ref().GetMouseX() > Position.X + c->Position.X && Engine::Ref().GetMouseX() < Position.X + c->Position.X + c->Size.X &&
+ Engine::Ref().GetMouseY() > Position.Y + c->Position.Y && Engine::Ref().GetMouseY() < Position.Y + c->Position.Y + c->Size.Y)
+ c->OnMouseEnter(Engine::Ref().GetMouseX() - (Position.X + c->Position.X), Engine::Ref().GetMouseY() - (Position.Y + c->Position.Y));
+ }
+ else
+ {
+ //Component already has a state, don't sad it
+ }
+}
+
+unsigned Window::GetComponentCount()
+{
+ return Components.size();
+}
+
+Component* Window::GetComponent(unsigned idx)
+{
+ return Components[idx];
+}
+
+void Window::RemoveComponent(Component* c)
+{
+ // remove component WITHOUT freeing it.
+ for(unsigned i = 0; i < Components.size(); ++i)
+ {
+ // find the appropriate component index
+ if(Components[i] == c)
+ {
+ //Make sure any events don't continue
+ halt = true;
+ if(Components[i]==focusedComponent_)
+ focusedComponent_ = NULL;
+
+ Components.erase(Components.begin() + i);
+
+ // we're done
+ return;
+ }
+ }
+}
+
+void Window::OnTryExit(ExitMethod method)
+{
+ if(cancelButton && method != MouseOutside)
+ cancelButton->DoAction();
+}
+
+void Window::OnTryOkay(OkayMethod method)
+{
+ if(okayButton)
+ okayButton->DoAction();
+}
+
+void Window::RemoveComponent(unsigned idx)
+{
+ halt = true;
+ // free component and remove it.
+ if(Components[idx]==focusedComponent_)
+ focusedComponent_ = NULL;
+ delete Components[idx];
+ Components.erase(Components.begin() + idx);
+}
+
+bool Window::IsFocused(const Component* c) const
+{
+ return c == focusedComponent_;
+}
+
+void Window::FocusComponent(Component* c)
+{
+ this->focusedComponent_ = c;
+}
+
+void Window::DoExit()
+{
+
+ OnExit();
+}
+
+void Window::DoInitialized()
+{
+
+ OnInitialized();
+}
+
+void Window::DoBlur()
+{
+
+ OnBlur();
+}
+
+void Window::DoFocus()
+{
+
+ OnFocus();
+}
+
+void Window::DoDraw()
+{
+ OnDraw();
+ //draw
+ for(int i = 0, sz = Components.size(); i < sz; ++i)
+ if(Components[i]->Visible)
+ {
+ if(AllowExclusiveDrawing)
+ {
+ Point scrpos(Components[i]->Position.X + Position.X, Components[i]->Position.Y + Position.Y);
+ Components[i]->Draw(scrpos);
+ }
+ else
+ {
+ if( Components[i]->Position.X+Position.X + Components[i]->Size.X >= 0 &&
+ Components[i]->Position.Y+Position.Y + Components[i]->Size.Y >= 0 &&
+ Components[i]->Position.X+Position.X < ui::Engine::Ref().GetWidth() &&
+ Components[i]->Position.Y+Position.Y < ui::Engine::Ref().GetHeight() )
+ {
+ Point scrpos(Components[i]->Position.X + Position.X, Components[i]->Position.Y + Position.Y);
+ Components[i]->Draw( Point(scrpos) );
+ }
+ }
+#ifdef DEBUG
+ if(debugMode)
+ {
+ if(focusedComponent_==Components[i])
+ {
+ ui::Engine::Ref().g->fillrect(Components[i]->Position.X+Position.X, Components[i]->Position.Y+Position.Y, Components[i]->Size.X, Components[i]->Size.Y, 0, 255, 0, 90);
+ }
+ else
+ {
+ ui::Engine::Ref().g->fillrect(Components[i]->Position.X+Position.X, Components[i]->Position.Y+Position.Y, Components[i]->Size.X, Components[i]->Size.Y, 255, 0, 0, 90);
+ }
+ }
+#endif
+ }
+#ifdef DEBUG
+ if(debugMode)
+ {
+ if(focusedComponent_)
+ {
+ int xPos = focusedComponent_->Position.X+focusedComponent_->Size.X+5+Position.X;
+ Graphics * g = ui::Engine::Ref().g;
+ char tempString[512];
+ char tempString2[512];
+
+ sprintf(tempString, "Position: L %d, R %d, T: %d, B: %d", focusedComponent_->Position.X, Size.X-(focusedComponent_->Position.X+focusedComponent_->Size.X), focusedComponent_->Position.Y, Size.Y-(focusedComponent_->Position.Y+focusedComponent_->Size.Y));
+ sprintf(tempString2, "Size: %d, %d", focusedComponent_->Size.X, focusedComponent_->Size.Y);
+
+ if(Graphics::textwidth(tempString)+xPos > XRES+BARSIZE)
+ xPos = XRES+BARSIZE-(Graphics::textwidth(tempString)+5);
+ if(Graphics::textwidth(tempString2)+xPos > XRES+BARSIZE)
+ xPos = XRES+BARSIZE-(Graphics::textwidth(tempString2)+5);
+
+ g->drawtext(xPos, focusedComponent_->Position.Y+Position.Y+1, tempString, 0, 0, 0, 200);
+ g->drawtext(xPos, focusedComponent_->Position.Y+Position.Y, tempString, 255, 255, 255, 255);
+ g->drawtext(xPos, focusedComponent_->Position.Y+Position.Y+13, tempString2, 0, 0, 0, 200);
+ g->drawtext(xPos, focusedComponent_->Position.Y+Position.Y+12, tempString2, 255, 255, 255, 255);
+ }
+ return;
+ }
+#endif
+
+}
+
+void Window::DoTick(float dt)
+{
+#ifdef DEBUG
+ if(debugMode)
+ return;
+#endif
+ //on mouse hover
+ for(int i = Components.size() - 1; i >= 0 && !halt; --i)
+ {
+ if(!Components[i]->Locked &&
+ ui::Engine::Ref().GetMouseX() >= Components[i]->Position.X+Position.X &&
+ ui::Engine::Ref().GetMouseY() >= Components[i]->Position.Y+Position.Y &&
+ ui::Engine::Ref().GetMouseX() < Components[i]->Position.X+Position.X + Components[i]->Size.X &&
+ ui::Engine::Ref().GetMouseY() < Components[i]->Position.Y+Position.Y + Components[i]->Size.Y )
+ {
+ Components[i]->OnMouseHover(ui::Engine::Ref().GetMouseX() - (Components[i]->Position.X + Position.X), ui::Engine::Ref().GetMouseY() - (Components[i]->Position.Y + Position.Y));
+ break;
+ }
+ }
+
+ //tick
+ for(int i = 0, sz = Components.size(); i < sz && !halt; ++i)
+ {
+ Components[i]->Tick(dt);
+ }
+
+ halt = false;
+ stop = false;
+
+ OnTick(dt);
+
+ if(destruct)
+ finalise();
+}
+
+void Window::DoKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt)
+{
+#ifdef DEBUG
+ if(key == KEY_TAB && ctrl)
+ debugMode = !debugMode;
+ if(debugMode)
+ {
+ if(focusedComponent_!=NULL)
+ {
+ if(shift)
+ {
+ if(key == KEY_UP)
+ focusedComponent_->Size.Y--;
+ if(key == KEY_DOWN)
+ focusedComponent_->Size.Y++;
+ if(key == KEY_LEFT)
+ focusedComponent_->Size.X--;
+ if(key == KEY_RIGHT)
+ focusedComponent_->Size.X++;
+ }
+ if(ctrl)
+ {
+ if(key == KEY_UP)
+ focusedComponent_->Size.Y++;
+ if(key == KEY_DOWN)
+ focusedComponent_->Size.Y--;
+ if(key == KEY_LEFT)
+ focusedComponent_->Size.X++;
+ if(key == KEY_RIGHT)
+ focusedComponent_->Size.X--;
+ }
+ if(!shift)
+ {
+ if(key == KEY_UP)
+ focusedComponent_->Position.Y--;
+ if(key == KEY_DOWN)
+ focusedComponent_->Position.Y++;
+ if(key == KEY_LEFT)
+ focusedComponent_->Position.X--;
+ if(key == KEY_RIGHT)
+ focusedComponent_->Position.X++;
+ }
+ if (key == KEY_DELETE)
+ {
+ RemoveComponent(focusedComponent_);
+ halt = false;
+ }
+ }
+ else
+ {
+ if(shift)
+ {
+ if(key == KEY_UP)
+ Size.Y--;
+ if(key == KEY_DOWN)
+ Size.Y++;
+ if(key == KEY_LEFT)
+ Size.X--;
+ if(key == KEY_RIGHT)
+ Size.X++;
+ }
+ if(ctrl)
+ {
+ if(key == KEY_UP)
+ Size.Y++;
+ if(key == KEY_DOWN)
+ Size.Y--;
+ if(key == KEY_LEFT)
+ Size.X++;
+ if(key == KEY_RIGHT)
+ Size.X--;
+ }
+ if(!shift)
+ {
+ if(key == KEY_UP)
+ Position.Y--;
+ if(key == KEY_DOWN)
+ Position.Y++;
+ if(key == KEY_LEFT)
+ Position.X--;
+ if(key == KEY_RIGHT)
+ Position.X++;
+ }
+ }
+ return;
+ }
+#endif
+ //on key press
+ if(focusedComponent_ != NULL)
+ {
+ if(!focusedComponent_->Locked && focusedComponent_->Visible)
+ focusedComponent_->OnKeyPress(key, character, shift, ctrl, alt);
+ }
+
+ if(!stop)
+ OnKeyPress(key, character, shift, ctrl, alt);
+
+ if(key == KEY_ESCAPE)
+ OnTryExit(Escape);
+
+ if(key == KEY_ENTER || key == KEY_RETURN)
+ OnTryOkay(Enter);
+
+ if(destruct)
+ finalise();
+}
+
+void Window::DoKeyRelease(int key, Uint16 character, bool shift, bool ctrl, bool alt)
+{
+#ifdef DEBUG
+ if(debugMode)
+ return;
+#endif
+ //on key unpress
+ if(focusedComponent_ != NULL)
+ {
+ if(!focusedComponent_->Locked && focusedComponent_->Visible)
+ focusedComponent_->OnKeyRelease(key, character, shift, ctrl, alt);
+ }
+
+ if(!stop)
+ OnKeyRelease(key, character, shift, ctrl, alt);
+ if(destruct)
+ finalise();
+}
+
+void Window::DoMouseDown(int x_, int y_, unsigned button)
+{
+ //on mouse click
+ int x = x_ - Position.X;
+ int y = y_ - Position.Y;
+ bool clickState = false;
+ for(int i = Components.size() - 1; i > -1 && !halt; --i)
+ {
+ if(!Components[i]->Locked && Components[i]->Visible)
+ {
+ if(x >= Components[i]->Position.X && y >= Components[i]->Position.Y && x < Components[i]->Position.X + Components[i]->Size.X && y < Components[i]->Position.Y + Components[i]->Size.Y)
+ {
+ FocusComponent(Components[i]);
+#ifdef DEBUG
+ if(!debugMode)
+#endif
+ Components[i]->OnMouseClick(x - Components[i]->Position.X, y - Components[i]->Position.Y, button);
+ clickState = true;
+ break;
+ }
+ }
+ }
+
+ if(!clickState)
+ FocusComponent(NULL);
+
+#ifdef DEBUG
+ if(debugMode)
+ return;
+#endif
+
+ //on mouse down
+ for(int i = Components.size() - 1; i > -1 && !halt; --i)
+ {
+ if(!Components[i]->Locked && Components[i]->Visible)
+ Components[i]->OnMouseDown(x, y, button);
+ }
+
+ if(!stop)
+ OnMouseDown(x_, y_, button);
+
+ if(!clickState && (x_ < Position.X || y_ < Position.Y || x_ > Position.X+Size.X || y_ > Position.Y+Size.Y))
+ OnTryExit(MouseOutside);
+
+ if(destruct)
+ finalise();
+}
+
+void Window::DoMouseMove(int x_, int y_, int dx, int dy)
+{
+ //on mouse move (if true, and inside)
+ int x = x_ - Position.X;
+ int y = y_ - Position.Y;
+#ifdef DEBUG
+ if(debugMode)
+ return;
+#endif
+ for(int i = Components.size() - 1; i > -1 && !halt; --i)
+ {
+ if(!Components[i]->Locked && Components[i]->Visible)
+ {
+ Point local (x - Components[i]->Position.X, y - Components[i]->Position.Y)
+ , a (local.X - dx, local.Y - dy);
+
+ Components[i]->OnMouseMoved(local.X, local.Y, dx, dy);
+
+ if(local.X >= 0 &&
+ local.Y >= 0 &&
+ local.X < Components[i]->Size.X &&
+ local.Y < Components[i]->Size.Y && !halt)
+ {
+ Components[i]->OnMouseMovedInside(local.X, local.Y, dx, dy);
+
+ // entering?
+ if(!(
+ a.X >= 0 &&
+ a.Y >= 0 &&
+ a.X < Components[i]->Size.X &&
+ a.Y < Components[i]->Size.Y ))
+ {
+ Components[i]->OnMouseEnter(local.X, local.Y);
+ }
+ }
+ else if(!halt)
+ {
+ // leaving?
+ if( a.X >= 0 &&
+ a.Y >= 0 &&
+ a.X < Components[i]->Size.X &&
+ a.Y < Components[i]->Size.Y )
+ {
+ Components[i]->OnMouseLeave(local.X, local.Y);
+ }
+
+ }
+ }
+ }
+
+ if(!stop)
+ OnMouseMove(x_, y_, dx, dy);
+ if(destruct)
+ finalise();
+}
+
+void Window::DoMouseUp(int x_, int y_, unsigned button)
+{
+ int x = x_ - Position.X;
+ int y = y_ - Position.Y;
+#ifdef DEBUG
+ if(debugMode)
+ return;
+#endif
+ //on mouse unclick
+ for(int i = Components.size() - 1; i >= 0 && !halt; --i)
+ {
+ if(!Components[i]->Locked && Components[i]->Visible)
+ {
+ if(x >= Components[i]->Position.X && y >= Components[i]->Position.Y && x < Components[i]->Position.X + Components[i]->Size.X && y < Components[i]->Position.Y + Components[i]->Size.Y)
+ {
+ Components[i]->OnMouseUnclick(x - Components[i]->Position.X, y - Components[i]->Position.Y, button);
+ break;
+ }
+ }
+ }
+
+ //on mouse up
+ for(int i = Components.size() - 1; i >= 0 && !halt; --i)
+ {
+ if(!Components[i]->Locked && Components[i]->Visible)
+ Components[i]->OnMouseUp(x, y, button);
+ }
+
+ if(!stop)
+ OnMouseUp(x_, y_, button);
+ if(destruct)
+ finalise();
+}
+
+void Window::DoMouseWheel(int x_, int y_, int d)
+{
+ int x = x_ - Position.X;
+ int y = y_ - Position.Y;
+#ifdef DEBUG
+ if(debugMode)
+ return;
+#endif
+ //on mouse wheel focused
+ for(int i = Components.size() - 1; i >= 0 && !halt; --i)
+ {
+ if(x >= Components[i]->Position.X && y >= Components[i]->Position.Y && x < Components[i]->Position.X + Components[i]->Size.X && y < Components[i]->Position.Y + Components[i]->Size.Y)
+ {
+ if(!Components[i]->Locked && Components[i]->Visible)
+ Components[i]->OnMouseWheelInside(x - Components[i]->Position.X, y - Components[i]->Position.Y, d);
+ break;
+ }
+ }
+
+ //on mouse wheel
+ for(int i = Components.size() - 1; i >= 0 && !halt; --i)
+ {
+ if(!Components[i]->Locked && Components[i]->Visible)
+ Components[i]->OnMouseWheel(x - Components[i]->Position.X, y - Components[i]->Position.Y, d);
+ }
+
+ if(!stop)
+ OnMouseWheel(x_, y_, d);
+
+ if(destruct)
+ finalise();
+}
+
+void Window::finalise()
+{
+ delete this;
+}
+
+void Window::SelfDestruct()
+{
+ destruct = true;
+ halt = true;
+ stop = true;
+}
+
+void Window::Halt()
+{
+ stop = true;
+ halt = true;
+}
+
diff --git a/src/gui/interface/Window.h b/src/gui/interface/Window.h
new file mode 100644
index 0000000..dafb910
--- /dev/null
+++ b/src/gui/interface/Window.h
@@ -0,0 +1,135 @@
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#include <vector>
+#include "gui/interface/Point.h"
+#include "Engine.h"
+
+namespace ui
+{
+
+enum ChromeStyle
+{
+ None, Title, Resizable
+};
+//class State;
+ class Engine;
+ class Component;
+ class Button;
+
+ /* class State
+ *
+ * A UI state. Contains all components.
+ */
+ class Window
+ {
+ public:
+ Point Position;
+ Point Size;
+
+ Window(Point _position, Point _size);
+ virtual ~Window();
+
+ void SetOkayButton(ui::Button * button) { okayButton = button; }
+ void SetCancelButton(ui::Button * button) { cancelButton = button; }
+
+ bool AllowExclusiveDrawing; //false will not call draw on objects outside of bounds
+
+ // Add Component to state
+ void AddComponent(Component* c);
+
+ // Get the number of components this state has.
+ unsigned GetComponentCount();
+
+ // Get component by index. (See GetComponentCount())
+ Component* GetComponent(unsigned idx);
+
+ // Remove a component from state. NOTE: This DOES NOT free component from memory.
+ void RemoveComponent(Component* c);
+
+ // Remove a component from state. NOTE: This WILL free component from memory.
+ void RemoveComponent(unsigned idx);
+
+ virtual void ToolTip(Component * sender, ui::Point mousePosition, std::string toolTip) {}
+
+ virtual void DoInitialized();
+ virtual void DoExit();
+ virtual void DoTick(float dt);
+ virtual void DoDraw();
+ virtual void DoFocus();
+ virtual void DoBlur();
+
+ virtual void DoMouseMove(int x, int y, int dx, int dy);
+ virtual void DoMouseDown(int x, int y, unsigned button);
+ virtual void DoMouseUp(int x, int y, unsigned button);
+ virtual void DoMouseWheel(int x, int y, int d);
+ virtual void DoKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt);
+ virtual void DoKeyRelease(int key, Uint16 character, bool shift, bool ctrl, bool alt);
+
+ //Sets halt and destroy, this causes the Windows to stop sending events and remove itself.
+ void SelfDestruct();
+ void Halt();
+
+ bool IsFocused(const Component* c) const;
+ void FocusComponent(Component* c);
+
+ void* UserData;
+
+ enum OkayMethod { Enter, OkayButton };
+ enum ExitMethod { MouseOutside, Escape, ExitButton };
+
+ protected:
+ ui::Button * okayButton;
+ ui::Button * cancelButton;
+
+ virtual void OnInitialized() {}
+ virtual void OnExit() {}
+ virtual void OnTick(float dt) {}
+ virtual void OnDraw() {}
+ virtual void OnFocus() {}
+ virtual void OnBlur() {}
+
+ virtual void OnTryExit(ExitMethod);
+ virtual void OnTryOkay(OkayMethod);
+
+ virtual void OnMouseMove(int x, int y, int dx, int dy) {}
+ virtual void OnMouseDown(int x, int y, unsigned button) {}
+ virtual void OnMouseUp(int x, int y, unsigned button) {}
+ virtual void OnMouseWheel(int x, int y, int d) {}
+ virtual void OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt) {}
+ virtual void OnKeyRelease(int key, Uint16 character, bool shift, bool ctrl, bool alt) {}
+ std::vector<Component*> Components;
+ Component* focusedComponent_;
+ ChromeStyle chrome;
+
+ //These controls allow a component to call the destruction of the Window inside an event (called by the Window)
+ void finalise();
+ bool halt;
+ bool destruct;
+ bool stop;
+#ifdef DEBUG
+ bool debugMode;
+#endif
+
+ };
+
+
+/*class Window : public State
+{
+private:
+ ChromeStyle chrome;
+public:
+ Window(Point _position, Point _size);
+ Point Position;
+ Point Size;
+
+ virtual void DoTick(float dt);
+ virtual void DoDraw();
+
+ virtual void DoMouseMove(int x, int y, int dx, int dy);
+ virtual void DoMouseDown(int x, int y, unsigned button);
+ virtual void DoMouseUp(int x, int y, unsigned button);
+ virtual void DoMouseWheel(int x, int y, int d);
+};*/
+}
+#endif // WINDOW_H