diff options
| author | Simon 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) |
| commit | 9abe51526cac2634af0541c3de69834dd30e9f78 (patch) | |
| tree | 6ae4deadfe00a83094b9d288d8c11d8ce823577a /src/gui/interface | |
| parent | 2c311b9a36a88fadd96f3d39acb1ab2590835d81 (diff) | |
| download | powder-9abe51526cac2634af0541c3de69834dd30e9f78.zip powder-9abe51526cac2634af0541c3de69834dd30e9f78.tar.gz | |
Move all GUI source files into gui/
Diffstat (limited to 'src/gui/interface')
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 |
