first commit

This commit is contained in:
Maschell 2020-10-02 19:57:53 +02:00
commit 25bcbf1727
37 changed files with 9176 additions and 0 deletions

17
.gitattributes vendored Normal file
View File

@ -0,0 +1,17 @@
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
build/*
release/*
libgui.cbp
lib/
*.bz2
libgui.layout
obj/
CMakeLists.txt
cmake-build-debug/
.idea/

11
Dockerfile.wiiu Normal file
View File

@ -0,0 +1,11 @@
FROM wiiuenv/devkitppc:20200810
RUN dkp-pacman -Syu && dkp-pacman -S --noconfirm wiiu-sdl2-libs && dkp-pacman -Scc --noconfirm
WORKDIR tmp_build
COPY . .
RUN make clean && make -j8 && mkdir -p /artifacts/wut/usr && cp -r lib /artifacts/wut/usr && cp -r include /artifacts/wut/usr
WORKDIR /artifacts
FROM scratch
COPY --from=0 /artifacts /artifacts

160
Makefile.wiiu Normal file
View File

@ -0,0 +1,160 @@
#-------------------------------------------------------------------------------
.SUFFIXES:
#-------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
endif
TOPDIR ?= $(CURDIR)
include $(DEVKITPRO)/wut/share/wut_rules
export VER_MAJOR := 1
export VER_MINOR := 0
export VER_PATCH := 0
VERSION := $(VER_MAJOR).$(VER_MINOR).$(VER_PATCH)
#-------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#-------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := source \
source/gui \
source/gui/input \
source/gui/system \
source/gui/video
DATA := data
INCLUDES := source \
include/gui-sdl \
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
CFLAGS := -Wall -Werror -save-temps \
-ffunction-sections -fdata-sections \
$(MACHDEP) \
$(BUILD_CFLAGS)
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
CXXFLAGS := $(CFLAGS) -std=gnu++20
ASFLAGS := $(MACHDEP)
LDFLAGS = $(ARCH) -Wl,--gc-sections
LIBS :=
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(WUT_ROOT)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
DEFFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.def)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(DEFFILES:.def=.o) $(SFILES:.s=.o) $(CFILES:.c=.o) $(CPPFILES:.cpp=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
export HFILES := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I. -I$(PORTLIBS_PATH)/ppc/include/freetype2
.PHONY: all dist-bin dist-src dist install clean
#---------------------------------------------------------------------------------
all: lib/libgui-sdl.a
dist-bin: all
@tar --exclude=*~ -cjf libgui-sdl-$(VERSION).tar.bz2 include lib
dist-src:
@tar --exclude=*~ -cjf libgui-sdl-src-$(VERSION).tar.bz2 include source Makefile.wiiu
dist: dist-src dist-bin
install: dist-bin
mkdir -p $(DESTDIR)$(DEVKITPRO)/wut/usr
bzip2 -cd libgui-sdl-$(VERSION).tar.bz2 | tar -xf - -C $(DESTDIR)$(DEVKITPRO)/wut/usr
lib:
@[ -d $@ ] || mkdir -p $@
release:
@[ -d $@ ] || mkdir -p $@
lib/libgui-sdl.a :$(SOURCES) $(INCLUDES) | lib release
@$(MAKE) -f $(CURDIR)/Makefile.wiiu BUILD=release OUTPUT=$(CURDIR)/$@ \
BUILD_CFLAGS="-DNDEBUG=1 -O2 -s" \
DEPSDIR=$(CURDIR)/release \
--no-print-directory -C release \
-f $(CURDIR)/Makefile.wiiu
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -rf release lib
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT) : $(OFILES)
$(OFILES_SRC) : $(HFILES)
#---------------------------------------------------------------------------------
%_bin.h %.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

12
README.md Normal file
View File

@ -0,0 +1,12 @@
# libgui-sdl
## Dependencies
To be able to use libgui, you need to install the following dependencies:
- [wut](https://github.com/devkitPro/wut/)
- Install the required portlibs and sdl2 via `(dkp-)pacman -Syu wiiu-portlibs wiiu-sdl2-libs`
# Credits
- Orignally based on https://github.com/dborth/libwiigui
- Wii U port / modification / new functions / sound / much more by dimok.

View File

@ -0,0 +1,130 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <gui/GuiElement.h>
#include <gui/GuiImage.h>
#include <gui/GuiText.h>
#include <gui/GuiSound.h>
#include <gui/GuiTrigger.h>
//!Display, manage, and manipulate buttons in the GUI. Buttons can have images, icons, text, and sound set (all of which are optional)
class GuiButton : public GuiElement {
public:
//!Constructor
//!\param w Width
//!\param h Height
GuiButton(float w, float h);
//!Destructor
virtual ~GuiButton();
//!Sets the button's image
//!\param i Pointer to GuiImage object
void setImage(GuiImage *i);
//!Sets the button's image on over
//!\param i Pointer to GuiImage object
void setImageOver(GuiImage *i);
void setIcon(GuiImage *i);
void setIconOver(GuiImage *i);
//!Sets the button's image on hold
//!\param i Pointer to GuiImage object
void setImageHold(GuiImage *i);
//!Sets the button's image on click
//!\param i Pointer to GuiImage object
void setImageClick(GuiImage *i);
//!Sets the button's label
//!\param t Pointer to GuiText object
//!\param n Index of label to set (optional, default is 0)
void setLabel(GuiText *t, int32_t n = 0);
//!Sets the button's label on over (eg: different colored text)
//!\param t Pointer to GuiText object
//!\param n Index of label to set (optional, default is 0)
void setLabelOver(GuiText *t, int32_t n = 0);
//!Sets the button's label on hold
//!\param t Pointer to GuiText object
//!\param n Index of label to set (optional, default is 0)
void setLabelHold(GuiText *t, int32_t n = 0);
//!Sets the button's label on click
//!\param t Pointer to GuiText object
//!\param n Index of label to set (optional, default is 0)
void setLabelClick(GuiText *t, int32_t n = 0);
//!Sets the sound to play on over
//!\param s Pointer to GuiSound object
void setSoundOver(GuiSound *s);
//!Sets the sound to play on hold
//!\param s Pointer to GuiSound object
void setSoundHold(GuiSound *s);
//!Sets the sound to play on click
//!\param s Pointer to GuiSound object
void setSoundClick(GuiSound *s);
//!Set a new GuiTrigger for the element
//!\param i Index of trigger array to set
//!\param t Pointer to GuiTrigger
void setTrigger(GuiTrigger *t, int32_t idx = -1);
//!
void resetState(void) override;
//!Constantly called to draw the GuiButton
void draw(Renderer *video) override;
//!Constantly called to allow the GuiButton to respond to updated input data
//!\param t Pointer to a GuiTrigger, containing the current input data from PAD/WPAD
void update(GuiController *c) override;
void process() override;
sigslot::signal2<GuiButton *, const GuiController *> selected;
sigslot::signal2<GuiButton *, const GuiController *> deSelected;
sigslot::signal2<GuiButton *, const GuiController *> pointedOn;
sigslot::signal2<GuiButton *, const GuiController *> pointedOff;
sigslot::signal3<GuiButton *, const GuiController *, GuiTrigger *> clicked;
sigslot::signal3<GuiButton *, const GuiController *, GuiTrigger *> held;
sigslot::signal3<GuiButton *, const GuiController *, GuiTrigger *> released;
protected:
static const int32_t iMaxGuiTriggers = 10;
GuiImage *image; //!< Button image (default)
GuiImage *imageOver; //!< Button image for STATE_SELECTED
GuiImage *imageHold; //!< Button image for STATE_HELD
GuiImage *imageClick; //!< Button image for STATE_CLICKED
GuiImage *icon;
GuiImage *iconOver;
GuiText *label[4]; //!< Label(s) to display (default)
GuiText *labelOver[4]; //!< Label(s) to display for STATE_SELECTED
GuiText *labelHold[4]; //!< Label(s) to display for STATE_HELD
GuiText *labelClick[4]; //!< Label(s) to display for STATE_CLICKED
GuiSound *soundOver; //!< Sound to play for STATE_SELECTED
GuiSound *soundHold; //!< Sound to play for STATE_HELD
GuiSound *soundClick; //!< Sound to play for STATE_CLICKED
GuiTrigger *trigger[iMaxGuiTriggers]; //!< GuiTriggers (input actions) that this element responds to
GuiTrigger *clickedTrigger;
GuiTrigger *heldTrigger;
};

View File

@ -0,0 +1,68 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <string.h>
#include "GuiTrigger.h"
class GuiController {
public:
//!Constructor
GuiController(int32_t channel)
: chan(channel) {
memset(&lastData, 0, sizeof(lastData));
memset(&data, 0, sizeof(data));
switch (chan) {
default:
case GuiTrigger::CHANNEL_1:
chanIdx = 0;
break;
case GuiTrigger::CHANNEL_2:
chanIdx = 1;
break;
case GuiTrigger::CHANNEL_3:
chanIdx = 2;
break;
case GuiTrigger::CHANNEL_4:
chanIdx = 3;
break;
case GuiTrigger::CHANNEL_5:
chanIdx = 4;
break;
}
}
//!Destructor
virtual ~GuiController() {}
typedef struct {
uint32_t buttons_h;
uint32_t buttons_d;
uint32_t buttons_r;
bool validPointer;
bool touched;
float pointerAngle;
int32_t x;
int32_t y;
} PadData;
uint32_t chan;
int32_t chanIdx;
PadData data;
PadData lastData;
};

View File

@ -0,0 +1,629 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <string>
#include <vector>
#include <malloc.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <cwchar>
#include <cmath>
#include <iostream>
#include "sigslot.h"
#include <gui/video/Renderer.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
enum {
EFFECT_NONE = 0x00,
EFFECT_SLIDE_TOP = 0x01,
EFFECT_SLIDE_BOTTOM = 0x02,
EFFECT_SLIDE_RIGHT = 0x04,
EFFECT_SLIDE_LEFT = 0x08,
EFFECT_SLIDE_IN = 0x10,
EFFECT_SLIDE_OUT = 0x20,
EFFECT_SLIDE_FROM = 0x40,
EFFECT_FADE = 0x80,
EFFECT_SCALE = 0x100,
EFFECT_COLOR_TRANSITION = 0x200
};
enum {
ALIGN_LEFT = 0x01,
ALIGN_CENTER = 0x02,
ALIGN_RIGHT = 0x04,
ALIGN_TOP = 0x10,
ALIGN_MIDDLE = 0x20,
ALIGN_BOTTOM = 0x40,
ALIGN_TOP_LEFT = ALIGN_LEFT | ALIGN_TOP,
ALIGN_TOP_CENTER = ALIGN_CENTER | ALIGN_TOP,
ALIGN_TOP_RIGHT = ALIGN_RIGHT | ALIGN_TOP,
ALIGN_CENTERED = ALIGN_CENTER | ALIGN_MIDDLE,
};
//!Forward declaration
class GuiController;
class SDLSystem;
//!Primary GUI class. Most other classes inherit from this class.
class GuiElement {
public:
//!Constructor
GuiElement();
//!Destructor
virtual ~GuiElement() = default;
//!Set the element's parent
//!\param e Pointer to parent element
virtual void setParent(GuiElement *e) {
parentElement = e;
}
//!Gets the element's parent
//!\return Pointer to parent element
virtual GuiElement *getParent() {
return parentElement;
}
//!Gets the current leftmost coordinate of the element
//!Considers horizontal alignment, x offset, width, and parent element's GetLeft() / GetWidth() values
//!\return left coordinate
virtual float getLeft();
//!Gets the current topmost coordinate of the element
//!Considers vertical alignment, y offset, height, and parent element's GetTop() / GetHeight() values
//!\return top coordinate
virtual float getTop();
//!Gets the current Z coordinate of the element
//!\return Z coordinate
virtual float getDepth() {
float zParent = 0.0f;
if (parentElement) {
zParent = parentElement->getDepth();
}
return zParent + zoffset;
}
virtual float getCenterX() {
float pCenterX = 0.0f;
if (parentElement) {
pCenterX = parentElement->getCenterX();
}
pCenterX += xoffset + xoffsetDyn;
if (alignment & ALIGN_LEFT) {
float pWidth = 0.0f;
float pScale = 0.0f;
if (parentElement) {
pWidth = parentElement->getWidth();
pScale = parentElement->getScaleX();
}
pCenterX -= pWidth * 0.5f * pScale - width * 0.5f * getScaleX();
} else if (alignment & ALIGN_RIGHT) {
float pWidth = 0.0f;
float pScale = 0.0f;
if (parentElement) {
pWidth = parentElement->getWidth();
pScale = parentElement->getScaleX();
}
pCenterX += pWidth * 0.5f * pScale - width * 0.5f * getScaleX();
}
return pCenterX;
}
virtual float getCenterY() {
float pCenterY = 0.0f;
if (parentElement) {
pCenterY = parentElement->getCenterY();
}
pCenterY += yoffset + yoffsetDyn;
if (alignment & ALIGN_TOP) {
float pHeight = 0.0f;
float pScale = 0.0f;
if (parentElement) {
pHeight = parentElement->getHeight();
pScale = parentElement->getScaleY();
}
pCenterY += pHeight * 0.5f * pScale + getHeight() * 0.5f * getScaleY();
} else if (alignment & ALIGN_BOTTOM) {
float pHeight = 0.0f;
float pScale = 0.0f;
if (parentElement) {
pHeight = parentElement->getHeight();
pScale = parentElement->getScaleY();
}
pCenterY -= pHeight * 0.5f * pScale - getHeight() * 0.5f * getScaleY();
}
return pCenterY;
}
//!Gets elements xoffset
virtual float getOffsetX() {
return xoffset;
}
//!Gets elements yoffset
virtual float getOffsetY() {
return yoffset;
}
//!Gets the current width of the element. Does not currently consider the scale
//!\return width
virtual float getWidth() {
return width;
};
//!Gets the height of the element. Does not currently consider the scale
//!\return height
virtual float getHeight() {
return height;
}
//!Sets the size (width/height) of the element
//!\param w Width of element
//!\param h Height of element
virtual void setSize(float w, float h) {
width = w;
height = h;
}
//!Sets the element's visibility
//!\param v Visibility (true = visible)
virtual void setVisible(bool v) {
visible = v;
visibleChanged(this, v);
}
//!Checks whether or not the element is visible
//!\return true if visible, false otherwise
virtual bool isVisible() const {
return !isStateSet(STATE_HIDDEN) && visible;
};
//!Checks whether or not the element is selectable
//!\return true if selectable, false otherwise
virtual bool isSelectable() {
return !isStateSet(STATE_DISABLED) && selectable;
}
virtual bool isDrawOverOnlyWhenSelected() {
return drawOverOnlyWhenSelected;
}
virtual void setdrawOverOnlyWhenSelected(bool s) {
drawOverOnlyWhenSelected = s;
}
//!Checks whether or not the element is clickable
//!\return true if clickable, false otherwise
virtual bool isClickable() {
return !isStateSet(STATE_DISABLED) && clickable;
}
//!Checks whether or not the element is holdable
//!\return true if holdable, false otherwise
virtual bool isHoldable() {
return !isStateSet(STATE_DISABLED) && holdable;
}
//!Sets whether or not the element is selectable
//!\param s Selectable
virtual void setSelectable(bool s) {
selectable = s;
}
//!Sets whether or not the element is clickable
//!\param c Clickable
virtual void setClickable(bool c) {
clickable = c;
}
//!Sets whether or not the element is holdable
//!\param c Holdable
virtual void setHoldable(bool d) {
holdable = d;
}
//!Sets the element's state
//!\param s State (STATE_DEFAULT, STATE_SELECTED, STATE_CLICKED, STATE_DISABLED)
//!\param c Controller channel (0-3, -1 = none)
virtual void setState(uint32_t s, int32_t c) {
if (c >= 0 && c < 5) {
state[c] |= s;
} else {
for (int32_t i = 0; i < 5; i++) {
state[i] |= s;
}
}
stateChan = c;
stateChanged(this, s, c);
}
virtual void clearState(uint32_t s, int32_t c) {
if (c >= 0 && c < 5) {
state[c] &= ~s;
} else {
for (unsigned int & i : state) {
i &= ~s;
}
}
stateChan = c;
stateChanged(this, s, c);
}
virtual bool isStateSet(uint32_t s, int32_t c = -1) const {
if (c >= 0 && c < 5) {
return (state[c] & s) != 0;
} else {
for (unsigned int i : state) {
if ((i & s) != 0) {
return true;
}
}
return false;
}
}
//!Gets the element's current state
//!\return state
virtual int32_t getState(int32_t c) {
return state[c];
};
//!Gets the controller channel that last changed the element's state
//!\return Channel number (0-3, -1 = no channel)
virtual int32_t getStateChan() {
return stateChan;
};
//!Resets the element's state to STATE_DEFAULT
virtual void resetState() {
for (unsigned int & i : state) {
i = STATE_DEFAULT;
}
stateChan = -1;
}
//!Sets the element's alpha value
//!\param a alpha value
virtual void setAlpha(float a) {
alpha = a;
}
//!Gets the element's alpha value
//!Considers alpha, alphaDyn, and the parent element's getAlpha() value
//!\return alpha
virtual float getAlpha() {
float a;
if (alphaDyn >= 0) {
a = alphaDyn;
} else {
a = alpha;
}
if (parentElement) {
a = (a * parentElement->getAlpha());
}
return a;
}
//!Sets the element's scale
//!\param s scale (1 is 100%)
virtual void setScale(float s) {
scaleX = s;
scaleY = s;
scaleZ = s;
}
//!Sets the element's scale
//!\param s scale (1 is 100%)
virtual void setScaleX(float s) {
scaleX = s;
}
//!Sets the element's scale
//!\param s scale (1 is 100%)
virtual void setScaleY(float s) {
scaleY = s;
}
//!Sets the element's scale
//!\param s scale (1 is 100%)
virtual void setScaleZ(float s) {
scaleZ = s;
}
//!Gets the element's current scale
//!Considers scale, scaleDyn, and the parent element's getScale() value
virtual float getScale() {
float s = 0.5f * (scaleX + scaleY) * scaleDyn;
if (parentElement) {
s *= parentElement->getScale();
}
return s;
}
//!Gets the element's current scale
//!Considers scale, scaleDyn, and the parent element's getScale() value
virtual float getScaleX() {
float s = scaleX * scaleDyn;
if (parentElement) {
s *= parentElement->getScaleX();
}
return s;
}
//!Gets the element's current scale
//!Considers scale, scaleDyn, and the parent element's getScale() value
virtual float getScaleY() {
float s = scaleY * scaleDyn;
if (parentElement) {
s *= parentElement->getScaleY();
}
return s;
}
//!Gets the element's current scale
//!Considers scale, scaleDyn, and the parent element's getScale() value
virtual float getScaleZ() {
float s = scaleZ;
if (parentElement) {
s *= parentElement->getScaleZ();
}
return s;
}
//!Checks whether rumble was requested by the element
//!\return true is rumble was requested, false otherwise
virtual bool isRumbleActive() {
return rumble;
}
//!Sets whether or not the element is requesting a rumble event
//!\param r true if requesting rumble, false if not
virtual void setRumble(bool r) {
rumble = r;
}
//!Set an effect for the element
//!\param e Effect to enable
//!\param a Amount of the effect (usage varies on effect)
//!\param t Target amount of the effect (usage varies on effect)
virtual void setEffect(uint32_t e, int32_t a, int32_t t);
//!Sets an effect to be enabled on wiimote cursor over
//!\param e Effect to enable
//!\param a Amount of the effect (usage varies on effect)
//!\param t Target amount of the effect (usage varies on effect)
virtual void setEffectOnOver(uint32_t e, int32_t a, int32_t t);
//!Shortcut to SetEffectOnOver(EFFECT_SCALE, 4, 110)
virtual void setEffectGrow() {
setEffectOnOver(EFFECT_SCALE, 4, 110);
}
//!Reset all applied effects
virtual void resetEffects();
//!Gets the current element effects
//!\return element effects
virtual int32_t getEffect() const {
return effects;
}
//!\return true if element animation is on going
virtual bool isAnimated() const {
return (parentElement != 0) && (getEffect() > 0);
}
//!Checks whether the specified coordinates are within the element's boundaries
//!\param x X coordinate
//!\param y Y coordinate
//!\return true if contained within, false otherwise
virtual bool isInside(float x, float y) {
float rotatedX = x;
float rotatedY = y;
if (getAngle() != 0.f) {
// translate input point
float tempX = x - getCenterX();
float tempY = y - getCenterY();
// Conver to Rad
auto angleInRad = (float) ((getAngle() * -1.0f) * M_PI / 180.0f);
// now apply rotation
rotatedX = tempX * cos((angleInRad)) - tempY * sin(angleInRad);
rotatedY = tempX * sin(angleInRad) + tempY * cos(angleInRad);
// translate back
rotatedX = rotatedX + getCenterX();
rotatedY = rotatedY + getCenterY();
}
return (rotatedX > (this->getCenterX() - getScaleX() * getWidth() * 0.5f)
&& rotatedX < (this->getCenterX() + getScaleX() * getWidth() * 0.5f)
&& rotatedY > (this->getCenterY() - getScaleY() * getHeight() * 0.5f)
&& rotatedY < (this->getCenterY() + getScaleY() * getHeight() * 0.5f));
}
//!Sets the element's position
//!\param x X coordinate
//!\param y Y coordinate
virtual void setPosition(float x, float y) {
xoffset = x;
yoffset = y;
}
//!Sets the element's position
//!\param x X coordinate
//!\param y Y coordinate
//!\param z Z coordinate
virtual void setPosition(float x, float y, float z) {
xoffset = x;
yoffset = y;
zoffset = z;
}
//!Gets whether or not the element is in STATE_SELECTED
//!\return true if selected, false otherwise
virtual int32_t getSelected() {
return -1;
}
//!Sets the element's alignment respective to its parent element
//!Bitwise ALIGN_LEFT | ALIGN_RIGHT | ALIGN_CENTRE, ALIGN_TOP, ALIGN_BOTTOM, ALIGN_MIDDLE)
//!\param align Alignment
virtual void setAlignment(int32_t a) {
alignment = a;
}
//!Gets the element's alignment
virtual int32_t getAlignment() const {
return alignment;
}
//!Angle of the object
virtual void setAngle(float a) {
angle = a;
}
//!Angle of the object
virtual float getAngle() const {
float r_angle = angle;
if (parentElement) { r_angle += parentElement->getAngle(); }
return r_angle;
}
//!Called constantly to allow the element to respond to the current input data
//!\param t Pointer to a GuiController, containing the current input data from PAD/WPAD/VPAD
virtual void update(GuiController *t) {}
//!Called constantly to redraw the element
virtual void draw(Renderer * v) {}
//!Called constantly to process stuff in the element
virtual void process() {}
//!Updates the element's effects (dynamic values)
//!Called by Draw(), used for animation purposes
virtual void updateEffects();
typedef struct _POINT {
int32_t x;
int32_t y;
} POINT;
enum {
STATE_DEFAULT = 0,
STATE_SELECTED = 0x01,
STATE_CLICKED = 0x02,
STATE_HELD = 0x04,
STATE_OVER = 0x08,
STATE_HIDDEN = 0x10,
STATE_DISABLE_INPUT = 0x20,
STATE_CLICKED_TOUCH = 0x40,
STATE_DISABLED = 0x80
};
//! Switch pointer from control to screen position
POINT PtrToScreen(POINT p) {
//! TODO for 3D
//POINT r = { p.x + getLeft(), p.y + getTop() };
return p;
}
//! Switch pointer screen to control position
POINT PtrToControl(POINT p) {
//! TODO for 3D
//POINT r = { p.x - getLeft(), p.y - getTop() };
return p;
}
//! Signals
sigslot::signal2<GuiElement *, bool> visibleChanged;
sigslot::signal3<GuiElement *, int32_t, int32_t> stateChanged;
sigslot::signal1<GuiElement *> effectFinished;
protected:
bool rumble; //!< Wiimote rumble (on/off) - set to on when this element requests a rumble event
bool visible; //!< Visibility of the element. If false, Draw() is skipped
bool selectable; //!< Whether or not this element selectable (can change to SELECTED state)
bool clickable; //!< Whether or not this element is clickable (can change to CLICKED state)
bool holdable; //!< Whether or not this element is holdable (can change to HELD state)
bool drawOverOnlyWhenSelected; //!< Whether or not this element is holdable (can change to HELD state)
float width; //!< Element width
float height; //!< Element height
float xoffset; //!< Element X offset
float yoffset; //!< Element Y offset
float zoffset; //!< Element Z offset
float alpha; //!< Element alpha value (0-255)
float angle; //!< Angle of the object (0-360)
float scaleX; //!< Element scale (1 = 100%)
float scaleY; //!< Element scale (1 = 100%)
float scaleZ; //!< Element scale (1 = 100%)
uint32_t alignment; //!< Horizontal element alignment, respective to parent element
uint32_t state[5]{}; //!< Element state (DEFAULT, SELECTED, CLICKED, DISABLED)
int32_t stateChan; //!< Which controller channel is responsible for the last change in state
GuiElement *parentElement; //!< Parent element
//! TODO: Move me to some Animator class
int32_t xoffsetDyn; //!< Element X offset, dynamic (added to xoffset value for animation effects)
int32_t yoffsetDyn; //!< Element Y offset, dynamic (added to yoffset value for animation effects)
float alphaDyn; //!< Element alpha, dynamic (multiplied by alpha value for blending/fading effects)
float scaleDyn; //!< Element scale, dynamic (multiplied by alpha value for blending/fading effects)
uint32_t effects; //!< Currently enabled effect(s). 0 when no effects are enabled
int32_t effectAmount; //!< Effect amount. Used by different effects for different purposes
int32_t effectTarget; //!< Effect target amount. Used by different effects for different purposes
uint32_t effectsOver; //!< Effects to enable when wiimote cursor is over this element. Copied to effects variable on over event
int32_t effectAmountOver; //!< EffectAmount to set when wiimote cursor is over this element
int32_t effectTargetOver; //!< EffectTarget to set when wiimote cursor is over this element
};

View File

@ -0,0 +1,109 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <vector>
#include <mutex>
#include <gui/GuiElement.h>
#include <gui/sigslot.h>
#include <gui/video/Renderer.h>
//!Allows GuiElements to be grouped together into a "window"
class GuiFrame : public GuiElement {
public:
//!Constructor
GuiFrame(GuiFrame *parent = 0);
//!\overload
//!\param w Width of window
//!\param h Height of window
GuiFrame(float w, float h, GuiFrame *parent = 0);
//!Destructor
~GuiFrame() override;
//!Appends a GuiElement to the GuiFrame
//!\param e The GuiElement to append. If it is already in the GuiFrame, it is removed first
void append(GuiElement *e);
//!Inserts a GuiElement into the GuiFrame at the specified index
//!\param e The GuiElement to insert. If it is already in the GuiFrame, it is removed first
//!\param i Index in which to insert the element
void insert(GuiElement *e, uint32_t i);
//!Removes the specified GuiElement from the GuiFrame
//!\param e GuiElement to be removed
void remove(GuiElement *e);
//!Removes all GuiElements
void removeAll();
//!Bring element to front of the window
void bringToFront(GuiElement *e) {
remove(e);
append(e);
}
//!Returns the GuiElement at the specified index
//!\param index The index of the element
//!\return A pointer to the element at the index, NULL on error (eg: out of bounds)
GuiElement *getGuiElementAt(uint32_t index) const;
//!Returns the size of the list of elements
//!\return The size of the current element list
uint32_t getSize();
//!Sets the visibility of the window
//!\param v visibility (true = visible)
void setVisible(bool v) override;
//!Resets the window's state to STATE_DEFAULT
void resetState() override;
//!Sets the window's state
//!\param s State
void setState(uint32_t s, int32_t c = -1) override;
void clearState(uint32_t s, int32_t c = -1) override;
//!Gets the index of the GuiElement inside the window that is currently selected
//!\return index of selected GuiElement
int32_t getSelected() override;
//!Draws all the elements in this GuiFrame
void draw(Renderer *v) override;
//!Updates the window and all elements contains within
//!Allows the GuiFrame and all elements to respond to the input data specified
//!\param t Pointer to a GuiTrigger, containing the current input data from PAD/WPAD
void update(GuiController *t) override;
//!virtual updateEffects which is called by the main loop
void updateEffects() override;
//!virtual process which is called by the main loop
void process() override;
//! Signals
//! On Closing
sigslot::signal1<GuiFrame *> closing;
protected:
bool dim; //! Enable/disable dim of a window only
GuiFrame *parent; //!< Parent Window
std::vector<GuiElement *> elements; //!< Contains all elements within the GuiFrame
std::recursive_mutex mutex;
};

View File

@ -0,0 +1,50 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <SDL2/SDL_render.h>
#include <gui/GuiElement.h>
#include <gui/GuiTextureData.h>
//!Display, manage, and manipulate images in the GUI
class GuiImage : public GuiElement {
public:
GuiImage() = default;
//! Draws an image from an existing texture
//!\param texture Pointer to GuiTextureData element
explicit GuiImage(GuiTextureData *texture);
//! Draws a colored rectangle
//!\param texture Pointer to GuiTextureData element
explicit GuiImage(SDL_Color color, float width, float height);
//!Destructor
~GuiImage() override;
void draw(Renderer *r) override;
void setTexture(GuiTextureData *tex);
private:
GuiTextureData *texture = nullptr;
bool freeTextureData = false;
// Color of the rect that's drawn if the picture has no texture.
SDL_Color color = {0, 0, 0, 0};
};

View File

@ -0,0 +1,67 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <gui/GuiElement.h>
#include <SDL2/SDL_mixer.h>
//!Sound conversion and playback. A wrapper for other sound libraries - ASND, libmad, ltremor, etc
class GuiSound : public GuiElement {
public:
explicit GuiSound(const char *filepath);
//!Constructor
//!\param sound Pointer to the sound data
//!\param filesize Length of sound data
GuiSound(void *buffer, uint32_t filesize, bool freeSrc = false);
//!Destructor
~GuiSound() override;
//!Load a file and replace the old one
bool Load(const char *filepath);
//!Start sound playback
void Play();
//!Stop sound playback
void Stop() const;
//!Pause sound playback
void Pause() const;
//!Resume sound playback
void Resume();
//!Checks if the sound is currently playing
//!\return true if sound is playing, false otherwise
[[nodiscard]] bool IsPlaying() const;
//!Rewind the music
void Rewind() const;
//!Set sound volume
//!\param v Sound volume (0-100)
void SetVolume(uint32_t v) const;
//!\param l Loop (true to loop)
void SetLoop(bool l);
Mix_Chunk *music = nullptr;
int32_t loops = 0;
int32_t playedOn = -1;
};

View File

@ -0,0 +1,56 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <gui/GuiElement.h>
#include <gui/GuiTextureData.h>
#include <gui/video/SDL_FontCache.h>
#include <gui/GuiImage.h>
#include <mutex>
#include <SDL2/SDL_ttf.h>
//!Display, manage, and manipulate text in the GUI
class GuiText : public GuiElement {
public:
//!\param t Text
//!\param s Font size
//!\param c Font color
GuiText(const std::string &t, SDL_Color c, FC_Font *font);
~GuiText() override;
void draw(Renderer *pVideo) override;
void process() override;
void setMaxWidth(float width);
protected:
GuiImage texture;
GuiTextureData* textureData = nullptr;
std::string text;
SDL_Color color;
FC_Font *fc_font = nullptr;
bool doUpdateTexture = true;
uint16_t maxWidth = 0xFFFF;
void updateSize();
void updateTexture(Renderer *renderer);
};

View File

@ -0,0 +1,41 @@
#pragma once
#include <SDL2/SDL_render.h>
#include <gui/GuiElement.h>
class GuiTextureData {
public:
GuiTextureData(void *buffer, uint32_t filesize, bool freesrc = false);
explicit GuiTextureData(SDL_Texture *texture);
explicit GuiTextureData(const std::string &path);
//!Destructor
~GuiTextureData();
void draw(Renderer *pVideo, const SDL_Rect &rect, float angle);
int setBlendMode(SDL_BlendMode blendMode);
[[nodiscard]] int32_t getWidth() const {
return width;
}
[[nodiscard]] int32_t getHeight() const {
return height;
}
protected:
void loadSurface(SDL_Surface *pSurface);
SDL_Surface *imgSurface = nullptr;
void cleanUp();
SDL_Texture *texture = nullptr;
int32_t width = 0;
int32_t height = 0;
SDL_BlendMode blendMode;
};

View File

@ -0,0 +1,132 @@
/***************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <cstdint>
class GuiController;
//!Menu input trigger management. Determine if action is necessary based on input data by comparing controller input data to a specific trigger element.
class GuiTrigger {
public:
enum eClicked {
CLICKED_NONE = 0x00,
CLICKED_TOUCH = 0x01,
CLICKED_BUTTON = 0x02,
};
enum eChannels {
CHANNEL_1 = 0x01,
CHANNEL_2 = 0x02,
CHANNEL_3 = 0x04,
CHANNEL_4 = 0x08,
CHANNEL_5 = 0x10,
CHANNEL_ALL = 0xFF
};
enum eButtons {
BUTTON_NONE = 0x0000,
TOUCHED = 0x80000000,
VPAD_TOUCH = TOUCHED,
BUTTON_Z = 0x20000,
BUTTON_C = 0x10000,
BUTTON_A = 0x8000,
BUTTON_B = 0x4000,
BUTTON_X = 0x2000,
BUTTON_Y = 0x1000,
BUTTON_1 = BUTTON_Y,
BUTTON_2 = BUTTON_X,
BUTTON_LEFT = 0x0800,
BUTTON_RIGHT = 0x0400,
BUTTON_UP = 0x0200,
BUTTON_DOWN = 0x0100,
BUTTON_ZL = 0x0080,
BUTTON_ZR = 0x0040,
BUTTON_L = 0x0020,
BUTTON_R = 0x0010,
BUTTON_PLUS = 0x0008,
BUTTON_MINUS = 0x0004,
BUTTON_HOME = 0x0002,
BUTTON_SYNC = 0x0001,
STICK_R_LEFT = 0x04000000,
STICK_R_RIGHT = 0x02000000,
STICK_R_UP = 0x01000000,
STICK_R_DOWN = 0x00800000,
STICK_L_LEFT = 0x40000000,
STICK_L_RIGHT = 0x20000000,
STICK_L_UP = 0x10000000,
STICK_L_DOWN = 0x08000000,
BUTTON_STICK_L = BUTTON_Z,
BUTTON_STICK_R = BUTTON_C,
};
//!Constructor
GuiTrigger();
//!Constructor
GuiTrigger(uint32_t ch, uint32_t btns, bool clickEverywhere = false, bool holdEverywhere = false, bool selectionClickEverywhere = false);
//!Destructor
virtual ~GuiTrigger();
//!Sets a simple trigger. Requires: element is selected, and trigger button is pressed
void setTrigger(uint32_t ch, uint32_t btns);
void setClickEverywhere(bool b) {
bClickEverywhere = b;
}
void setHoldOnly(bool b) {
bHoldEverywhere = b;
}
void setSelectionClickEverywhere(bool b) {
bSelectionClickEverywhere = b;
}
[[nodiscard]] bool isClickEverywhere() const {
return bClickEverywhere;
}
[[nodiscard]] bool isHoldEverywhere() const {
return bHoldEverywhere;
}
[[nodiscard]] bool isSelectionClickEverywhere() const {
return bSelectionClickEverywhere;
}
bool left(const GuiController *controller) const;
bool right(const GuiController *controller) const;
bool up(const GuiController *controller) const;
bool down(const GuiController *controller) const;
int32_t clicked(const GuiController *controller) const;
bool held(const GuiController *controller) const;
bool released(const GuiController *controller) const;
private:
uint32_t chan;
uint32_t btns;
bool bClickEverywhere;
bool bHoldEverywhere;
bool bSelectionClickEverywhere;
bool bLastTouched;
};

View File

@ -0,0 +1,37 @@
#pragma once
#include <map>
#include <functional>
#include <gui/GuiTrigger.h>
#include <gui/input/SDLController.h>
#include <gui/input/SDLControllerMouse.h>
class ControllerManager {
public:
ControllerManager(int32_t screenWidth, int32_t screenHeight) : screenWidth(screenWidth), screenHeight(screenHeight){
}
void attachController(GuiTrigger::eChannels channels, SDLController *controller);
void prepare();
bool attachJoystick(int32_t deviceId);
void detachJoystick(int32_t deviceId);
void processEvent(SDL_JoystickID joystickId, int32_t channel, SDL_Event *event);
void finish();
void callPerController(std::function<void(GuiController*)> func);
private:
GuiTrigger::eChannels increaseChannel(GuiTrigger::eChannels channel);
std::map<GuiTrigger::eChannels, SDLController *> controllerList;
std::map<int32_t, GuiTrigger::eChannels> joystickToChannel;
int32_t screenWidth;
int32_t screenHeight;
};

View File

@ -0,0 +1,60 @@
#pragma once
#include <SDL2/SDL_mouse.h>
#include <iostream>
#include <SDL2/SDL_events.h>
#include <gui/GuiController.h>
#include <gui/system/libgui_log.h>
#define printButton(chan, x) if(data.buttons_d & x) LG_Log("Controller #%d %s", chan, #x)
class SDLController : public GuiController {
public:
explicit SDLController(int32_t channel) : GuiController(channel) {
}
virtual bool update(SDL_Event *e, int32_t screenWidth, int32_t screenHeight) = 0;
virtual void before() {
lastData = data;
data.buttons_d = 0;
data.buttons_r = 0;
}
virtual void after() {
data.buttons_d |= (data.buttons_h & (~(lastData.buttons_h)));
data.buttons_r |= ((lastData.buttons_h) & (~data.buttons_h));
if (data.buttons_h != 0 || data.buttons_d != 0 || data.buttons_r != 0) {
LG_Log("Controller #%d: h %08X d %08X r %08X", chanIdx, data.buttons_h, data.buttons_d, data.buttons_r);
printButton(chanIdx, GuiTrigger::BUTTON_A);
printButton(chanIdx, GuiTrigger::BUTTON_B);
printButton(chanIdx, GuiTrigger::BUTTON_X);
printButton(chanIdx, GuiTrigger::BUTTON_Y);
printButton(chanIdx, GuiTrigger::BUTTON_STICK_L);
printButton(chanIdx, GuiTrigger::BUTTON_STICK_R);
printButton(chanIdx, GuiTrigger::BUTTON_L);
printButton(chanIdx, GuiTrigger::BUTTON_R);
printButton(chanIdx, GuiTrigger::BUTTON_ZL);
printButton(chanIdx, GuiTrigger::BUTTON_ZR);
printButton(chanIdx, GuiTrigger::BUTTON_PLUS);
printButton(chanIdx, GuiTrigger::BUTTON_MINUS);
printButton(chanIdx, GuiTrigger::BUTTON_LEFT);
printButton(chanIdx, GuiTrigger::BUTTON_UP);
printButton(chanIdx, GuiTrigger::BUTTON_RIGHT);
printButton(chanIdx, GuiTrigger::BUTTON_DOWN);
printButton(chanIdx, GuiTrigger::STICK_L_LEFT);
printButton(chanIdx, GuiTrigger::STICK_L_UP);
printButton(chanIdx, GuiTrigger::STICK_L_RIGHT);
printButton(chanIdx, GuiTrigger::STICK_L_DOWN);
printButton(chanIdx, GuiTrigger::STICK_R_LEFT);
printButton(chanIdx, GuiTrigger::STICK_R_UP);
printButton(chanIdx, GuiTrigger::STICK_R_RIGHT);
printButton(chanIdx, GuiTrigger::STICK_R_DOWN);
printButton(chanIdx, GuiTrigger::TOUCHED);
}
}
};

View File

@ -0,0 +1,58 @@
#pragma once
class SDLControllerJoystick : public SDLController {
public:
SDLControllerJoystick(int32_t channel, SDL_JoystickID joystickId) : SDLController(channel) {
}
bool update(SDL_Event *e, int32_t screenWidth, int32_t screenHeight) override {
if (e->type == SDL_JOYBUTTONDOWN) {
data.buttons_h |= (1 << e->jbutton.button);
} else if (e->type == SDL_JOYBUTTONUP) {
data.buttons_h &= ~(1 << e->jbutton.button);
} else if (e->type == SDL_JOYHATMOTION) {
auto val = e->jhat.value;
auto hatMask = (GuiTrigger::BUTTON_LEFT | GuiTrigger::BUTTON_UP | GuiTrigger::BUTTON_DOWN | GuiTrigger::BUTTON_RIGHT);
// Remove hat values so we can add the new value.
data.buttons_h &= ~hatMask;
switch (val) {
case SDL_HAT_LEFTUP:
data.buttons_h |= GuiTrigger::BUTTON_LEFT;
data.buttons_h |= GuiTrigger::BUTTON_UP;
break;
case SDL_HAT_LEFT:
data.buttons_h |= GuiTrigger::BUTTON_LEFT;
break;
case SDL_HAT_LEFTDOWN:
data.buttons_h |= GuiTrigger::BUTTON_LEFT;
data.buttons_h |= GuiTrigger::BUTTON_DOWN;
break;
case SDL_HAT_UP:
data.buttons_h |= GuiTrigger::BUTTON_UP;
break;
case SDL_HAT_DOWN:
data.buttons_h |= GuiTrigger::BUTTON_DOWN;
break;
case SDL_HAT_RIGHTUP:
data.buttons_h |= GuiTrigger::BUTTON_RIGHT;
data.buttons_h |= GuiTrigger::BUTTON_UP;
break;
case SDL_HAT_RIGHT:
data.buttons_h |= GuiTrigger::BUTTON_RIGHT;
break;
case SDL_HAT_RIGHTDOWN:
data.buttons_h |= GuiTrigger::BUTTON_RIGHT;
data.buttons_h |= GuiTrigger::BUTTON_DOWN;
break;
}
} else if (e->type == SDL_JOYAXISMOTION) {
//
}
return true;
}
};

View File

@ -0,0 +1,29 @@
#pragma once
class SDLControllerMouse: public SDLController {
public:
explicit SDLControllerMouse(int32_t channel) : SDLController(channel) {
}
void before() override{
SDLController::before();
data.validPointer = true;
}
virtual bool update(SDL_Event *e, int32_t screenWidth, int32_t screenHeight) override {
if (e->type == SDL_MOUSEMOTION) {
data.y = e->motion.y;
data.x = e->motion.x;
} else if (e->type == SDL_MOUSEBUTTONDOWN && e->button.button == SDL_BUTTON_LEFT) {
data.touched = true;
} else if (e->type == SDL_MOUSEBUTTONUP && e->button.button == SDL_BUTTON_LEFT) {
data.touched = false;
}else{
LG_Log("Unknown event");
return false;
}
return true;
}
};

View File

@ -0,0 +1,50 @@
#pragma once
#include "SDLController.h"
static GuiTrigger::eButtons vpad_button_map[] = {
GuiTrigger::BUTTON_A,
GuiTrigger::BUTTON_B,
GuiTrigger::BUTTON_X,
GuiTrigger::BUTTON_Y,
GuiTrigger::BUTTON_STICK_L, GuiTrigger::BUTTON_STICK_R,
GuiTrigger::BUTTON_L, GuiTrigger::BUTTON_R,
GuiTrigger::BUTTON_ZL, GuiTrigger::BUTTON_ZR,
GuiTrigger::BUTTON_PLUS, GuiTrigger::BUTTON_MINUS,
GuiTrigger::BUTTON_LEFT, GuiTrigger::BUTTON_UP, GuiTrigger::BUTTON_RIGHT, GuiTrigger::BUTTON_DOWN,
GuiTrigger::STICK_L_LEFT, GuiTrigger::STICK_L_UP, GuiTrigger::STICK_L_RIGHT, GuiTrigger::STICK_L_DOWN,
GuiTrigger::STICK_R_LEFT, GuiTrigger::STICK_R_UP, GuiTrigger::STICK_R_RIGHT, GuiTrigger::STICK_R_DOWN,
};
class SDLControllerWiiUGamepad : public SDLController {
public:
explicit SDLControllerWiiUGamepad(int32_t channel) : SDLController(channel) {
}
bool update(SDL_Event *e, int32_t screenWidth, int32_t screenHeight) override {
if (e->type == SDL_FINGERMOTION || e->type == SDL_FINGERUP || e->type == SDL_FINGERDOWN) {
data.y = e->tfinger.y * screenHeight;
data.x = e->tfinger.x * screenWidth;
if (e->type == SDL_FINGERUP) {
data.touched = false;
} else if (e->type == SDL_FINGERDOWN) {
data.touched = true;
}
} else if (e->type == SDL_JOYBUTTONDOWN) {
data.buttons_h |= vpad_button_map[e->jbutton.button];
} else if (e->type == SDL_JOYBUTTONUP) {
data.buttons_h &= ~vpad_button_map[e->jbutton.button];
} else {
LG_Log("Unknown event");
return false;
}
return true;
}
void after() override {
data.validPointer = data.touched;
SDLController::after();
}
};

View File

@ -0,0 +1,11 @@
#pragma once
#include "SDLControllerWiiUGamepad.h"
class SDLControllerWiiUProContoller : public SDLControllerWiiUGamepad {
public:
explicit SDLControllerWiiUProContoller(int32_t channel) : SDLControllerWiiUGamepad(channel){
}
};

View File

@ -0,0 +1,106 @@
#pragma once
#include "SDLController.h"
static GuiTrigger::eButtons xbox_button_map[] =
{
GuiTrigger::BUTTON_A,
GuiTrigger::BUTTON_B,
GuiTrigger::BUTTON_X,
GuiTrigger::BUTTON_Y,
GuiTrigger::BUTTON_L,
GuiTrigger::BUTTON_R,
GuiTrigger::BUTTON_MINUS,
GuiTrigger::BUTTON_PLUS,
GuiTrigger::BUTTON_STICK_L,
GuiTrigger::BUTTON_STICK_R,
};
#define getDigitalAxis(axis, targetAxis, value, hold, first, second) \
if(axis == targetAxis){ \
if (value < 0x4000 && value > -0x4000){ \
hold &= ~first; \
hold &= ~second; \
}else if(value < -0x4000){ \
hold |= first; \
hold &= ~second; \
}else if(value > 0x4000){ \
hold |= second; \
hold &= ~first; \
} \
} \
#define getDigitalTrigger(axis, targetAxis, value, hold, first) \
if(axis == targetAxis){ \
if(value > 0){ \
hold |= first; \
}else{ \
hold &= ~first; \
} \
} \
class SDLControllerXboxOne : public SDLController {
public:
explicit SDLControllerXboxOne(int32_t channel) : SDLController(channel) {
}
bool update(SDL_Event *e, int32_t screenWidth, int32_t screenHeight) override {
if (e->type == SDL_JOYBUTTONDOWN) {
data.buttons_h |= xbox_button_map[e->jbutton.button];
} else if (e->type == SDL_JOYBUTTONUP) {
data.buttons_h &= ~xbox_button_map[e->jbutton.button];
} else if (e->type == SDL_JOYHATMOTION) {
auto val = e->jhat.value;
auto hatMask = (GuiTrigger::BUTTON_LEFT | GuiTrigger::BUTTON_UP | GuiTrigger::BUTTON_DOWN | GuiTrigger::BUTTON_RIGHT);
// Remove hat values so we can add the new values.
data.buttons_h &= ~hatMask;
switch (val) {
case SDL_HAT_LEFTUP:
data.buttons_h |= GuiTrigger::BUTTON_LEFT;
data.buttons_h |= GuiTrigger::BUTTON_UP;
break;
case SDL_HAT_LEFT:
data.buttons_h |= GuiTrigger::BUTTON_LEFT;
break;
case SDL_HAT_LEFTDOWN:
data.buttons_h |= GuiTrigger::BUTTON_LEFT;
data.buttons_h |= GuiTrigger::BUTTON_DOWN;
break;
case SDL_HAT_UP:
data.buttons_h |= GuiTrigger::BUTTON_UP;
break;
case SDL_HAT_DOWN:
data.buttons_h |= GuiTrigger::BUTTON_DOWN;
break;
case SDL_HAT_RIGHTUP:
data.buttons_h |= GuiTrigger::BUTTON_RIGHT;
data.buttons_h |= GuiTrigger::BUTTON_UP;
break;
case SDL_HAT_RIGHT:
data.buttons_h |= GuiTrigger::BUTTON_RIGHT;
break;
case SDL_HAT_RIGHTDOWN:
data.buttons_h |= GuiTrigger::BUTTON_RIGHT;
data.buttons_h |= GuiTrigger::BUTTON_DOWN;
break;
}
} else if (e->type == SDL_JOYAXISMOTION) {
getDigitalTrigger(e->jaxis.axis, 2, e->jaxis.value, data.buttons_h, GuiTrigger::BUTTON_ZL);
getDigitalTrigger(e->jaxis.axis, 5, e->jaxis.value, data.buttons_h, GuiTrigger::BUTTON_ZR);
getDigitalAxis(e->jaxis.axis, 0, e->jaxis.value, data.buttons_h, GuiTrigger::STICK_L_LEFT, GuiTrigger::STICK_L_RIGHT);
getDigitalAxis(e->jaxis.axis, 1, e->jaxis.value, data.buttons_h, GuiTrigger::STICK_L_UP, GuiTrigger::STICK_L_DOWN);
getDigitalAxis(e->jaxis.axis, 3, e->jaxis.value, data.buttons_h, GuiTrigger::STICK_R_LEFT, GuiTrigger::STICK_R_RIGHT);
getDigitalAxis(e->jaxis.axis, 4, e->jaxis.value, data.buttons_h, GuiTrigger::STICK_R_UP, GuiTrigger::STICK_R_DOWN);
} else {
LG_Log("Unknown event");
return false;
}
return true;
}
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <SDL2/SDL_render.h>
#include <gui/video/Renderer.h>
class SDLSystem {
public:
SDLSystem();
virtual ~SDLSystem();
Renderer *getRenderer();
float getHeight();
float getWidth();
private:
SDL_Window *window = NULL;
Renderer *renderer = NULL;
};

View File

@ -0,0 +1,8 @@
#pragma once
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
#define LG_Log(FMT, ARGS...)do { \
printf("[%23s]%30s@L%04d: " FMT "\n",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
} while (0)

View File

@ -0,0 +1,28 @@
#pragma once
#include <SDL2/SDL_render.h>
class Renderer {
public:
Renderer(SDL_Renderer *renderer, uint32_t pixelFormat) : sdl_renderer(renderer), pixelFormat(pixelFormat){
}
virtual ~Renderer() {
if(sdl_renderer){
SDL_DestroyRenderer(sdl_renderer);
}
}
SDL_Renderer *getRenderer(){
return sdl_renderer;
}
uint32_t getPixelFormat(){
return pixelFormat;
}
private:
SDL_Renderer *sdl_renderer = NULL;
uint32_t pixelFormat = SDL_PIXELFORMAT_RGBA8888;
};

View File

@ -0,0 +1,320 @@
/*
SDL_FontCache v0.10.0: A font cache for SDL and SDL_ttf
by Jonathan Dearborn
Dedicated to the memory of Florian Hufsky
License:
The short:
Use it however you'd like, but keep the copyright and license notice
whenever these files or parts of them are distributed in uncompiled form.
The long:
Copyright (c) 2019 Jonathan Dearborn
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef _SDL_FONTCACHE_H__
#define _SDL_FONTCACHE_H__
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <SDL2/SDL_pixels.h>
#include <gui/system/libgui_log.h>
#ifdef FC_USE_SDL_GPU
#include "SDL_gpu.h"
#endif
#include <stdarg.h>
#ifdef __cplusplus
extern "C" {
#endif
// Let's pretend this exists...
#define TTF_STYLE_OUTLINE 16
// Differences between SDL_Renderer and SDL_gpu
#ifdef FC_USE_SDL_GPU
#define FC_Rect GPU_Rect
#define FC_Target GPU_Target
#define FC_Image GPU_Image
#define FC_Log GPU_LogError
#else
#define FC_Rect SDL_Rect
#define FC_Target SDL_Renderer
#define FC_Image SDL_Texture
#define FC_Log LG_Log
#endif
// SDL_FontCache types
typedef enum
{
FC_ALIGN_LEFT,
FC_ALIGN_CENTER,
FC_ALIGN_RIGHT
} FC_AlignEnum;
typedef enum
{
FC_FILTER_NEAREST,
FC_FILTER_LINEAR
} FC_FilterEnum;
typedef struct FC_Scale
{
float x;
float y;
} FC_Scale;
typedef struct FC_Effect
{
FC_AlignEnum alignment;
FC_Scale scale;
SDL_Color color;
} FC_Effect;
// Opaque type
typedef struct FC_Font FC_Font;
typedef struct FC_GlyphData
{
SDL_Rect rect;
int cache_level;
} FC_GlyphData;
// Object creation
FC_Rect FC_MakeRect(float x, float y, float w, float h);
FC_Scale FC_MakeScale(float x, float y);
SDL_Color FC_MakeColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a);
FC_Effect FC_MakeEffect(FC_AlignEnum alignment, FC_Scale scale, SDL_Color color);
FC_GlyphData FC_MakeGlyphData(int cache_level, Sint16 x, Sint16 y, Uint16 w, Uint16 h);
// Font object
FC_Font* FC_CreateFont(void);
#ifdef FC_USE_SDL_GPU
Uint8 FC_LoadFont(FC_Font* font, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style);
Uint8 FC_LoadFontFromTTF(FC_Font* font, TTF_Font* ttf, SDL_Color color);
Uint8 FC_LoadFont_RW(FC_Font* font, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style);
#else
Uint8 FC_LoadFont(FC_Font* font, SDL_Renderer* renderer, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style);
Uint8 FC_LoadFontFromTTF(FC_Font* font, SDL_Renderer* renderer, TTF_Font* ttf, SDL_Color color);
Uint8 FC_LoadFont_RW(FC_Font* font, SDL_Renderer* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style);
#endif
#ifndef FC_USE_SDL_GPU
// note: handle SDL event types SDL_RENDER_TARGETS_RESET(>= SDL 2.0.2) and SDL_RENDER_DEVICE_RESET(>= SDL 2.0.4)
void FC_ResetFontFromRendererReset(FC_Font* font, SDL_Renderer* renderer, Uint32 evType);
#endif
void FC_ClearFont(FC_Font* font);
void FC_FreeFont(FC_Font* font);
// Built-in loading strings
char* FC_GetStringASCII(void);
char* FC_GetStringLatin1(void);
char* FC_GetStringASCII_Latin1(void);
// UTF-8 to SDL_FontCache codepoint conversion
/*!
Returns the Uint32 codepoint (not UTF-32) parsed from the given UTF-8 string.
\param c A pointer to a string of proper UTF-8 character values.
\param advance_pointer If true, the source pointer will be incremented to skip the extra bytes from multibyte codepoints.
*/
Uint32 FC_GetCodepointFromUTF8(const char** c, Uint8 advance_pointer);
/*!
Parses the given codepoint and stores the UTF-8 bytes in 'result'. The result is NULL terminated.
\param result A memory buffer for the UTF-8 values. Must be at least 5 bytes long.
\param codepoint The Uint32 codepoint to parse (not UTF-32).
*/
void FC_GetUTF8FromCodepoint(char* result, Uint32 codepoint);
// UTF-8 string operations
/*! Allocates a new string of 'size' bytes that is already NULL-terminated. The NULL byte counts toward the size limit, as usual. Returns NULL if size is 0. */
char* U8_alloc(unsigned int size);
/*! Deallocates the given string. */
void U8_free(char* string);
/*! Allocates a copy of the given string. */
char* U8_strdup(const char* string);
/*! Returns the number of UTF-8 characters in the given string. */
int U8_strlen(const char* string);
/*! Returns the number of bytes in the UTF-8 multibyte character pointed at by 'character'. */
int U8_charsize(const char* character);
/*! Copies the source multibyte character into the given buffer without overrunning it. Returns 0 on failure. */
int U8_charcpy(char* buffer, const char* source, int buffer_size);
/*! Returns a pointer to the next UTF-8 character. */
const char* U8_next(const char* string);
/*! Inserts a UTF-8 string into 'string' at the given position. Use a position of -1 to append. Returns 0 when unable to insert the string. */
int U8_strinsert(char* string, int position, const char* source, int max_bytes);
/*! Erases the UTF-8 character at the given position, moving the subsequent characters down. */
void U8_strdel(char* string, int position);
// Internal settings
/*! Sets the string from which to load the initial glyphs. Use this if you need upfront loading for any reason (such as lack of render-target support). */
void FC_SetLoadingString(FC_Font* font, const char* string);
/*! Returns the size of the internal buffer which is used for unpacking variadic text data. This buffer is shared by all FC_Fonts. */
unsigned int FC_GetBufferSize(void);
/*! Changes the size of the internal buffer which is used for unpacking variadic text data. This buffer is shared by all FC_Fonts. */
void FC_SetBufferSize(unsigned int size);
/*! Returns the width of a single horizontal tab in multiples of the width of a space (default: 4) */
unsigned int FC_GetTabWidth(void);
/*! Changes the width of a horizontal tab in multiples of the width of a space (default: 4) */
void FC_SetTabWidth(unsigned int width_in_spaces);
void FC_SetRenderCallback(FC_Rect (*callback)(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale));
FC_Rect FC_DefaultRenderCallback(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale);
// Custom caching
/*! Returns the number of cache levels that are active. */
int FC_GetNumCacheLevels(FC_Font* font);
/*! Returns the cache source texture at the given cache level. */
FC_Image* FC_GetGlyphCacheLevel(FC_Font* font, int cache_level);
// TODO: Specify ownership of the texture (should be shareable)
/*! Sets a cache source texture for rendering. New cache levels must be sequential. */
Uint8 FC_SetGlyphCacheLevel(FC_Font* font, int cache_level, FC_Image* cache_texture);
/*! Copies the given surface to the given cache level as a texture. New cache levels must be sequential. */
Uint8 FC_UploadGlyphCache(FC_Font* font, int cache_level, SDL_Surface* data_surface);
/*! Returns the number of codepoints that are stored in the font's glyph data map. */
unsigned int FC_GetNumCodepoints(FC_Font* font);
/*! Copies the stored codepoints into the given array. */
void FC_GetCodepoints(FC_Font* font, Uint32* result);
/*! Stores the glyph data for the given codepoint in 'result'. Returns 0 if the codepoint was not found in the cache. */
Uint8 FC_GetGlyphData(FC_Font* font, FC_GlyphData* result, Uint32 codepoint);
/*! Sets the glyph data for the given codepoint. Duplicates are not checked. Returns a pointer to the stored data. */
FC_GlyphData* FC_SetGlyphData(FC_Font* font, Uint32 codepoint, FC_GlyphData glyph_data);
// Rendering
FC_Rect FC_Draw(FC_Font* font, FC_Target* dest, float x, float y, const char* formatted_text, ...);
FC_Rect FC_DrawAlign(FC_Font* font, FC_Target* dest, float x, float y, FC_AlignEnum align, const char* formatted_text, ...);
FC_Rect FC_DrawScale(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* formatted_text, ...);
FC_Rect FC_DrawColor(FC_Font* font, FC_Target* dest, float x, float y, SDL_Color color, const char* formatted_text, ...);
FC_Rect FC_DrawEffect(FC_Font* font, FC_Target* dest, float x, float y, FC_Effect effect, const char* formatted_text, ...);
FC_Rect FC_DrawBox(FC_Font* font, FC_Target* dest, FC_Rect box, const char* formatted_text, ...);
FC_Rect FC_DrawBoxAlign(FC_Font* font, FC_Target* dest, FC_Rect box, FC_AlignEnum align, const char* formatted_text, ...);
FC_Rect FC_DrawBoxScale(FC_Font* font, FC_Target* dest, FC_Rect box, FC_Scale scale, const char* formatted_text, ...);
FC_Rect FC_DrawBoxColor(FC_Font* font, FC_Target* dest, FC_Rect box, SDL_Color color, const char* formatted_text, ...);
FC_Rect FC_DrawBoxEffect(FC_Font* font, FC_Target* dest, FC_Rect box, FC_Effect effect, const char* formatted_text, ...);
FC_Rect FC_DrawColumn(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, const char* formatted_text, ...);
FC_Rect FC_DrawColumnToTexture(FC_Font* font, SDL_Texture* target, float x, float y, Uint16 width, const char* text);
FC_Rect FC_DrawColumnAlign(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_AlignEnum align, const char* formatted_text, ...);
FC_Rect FC_DrawColumnScale(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_Scale scale, const char* formatted_text, ...);
FC_Rect FC_DrawColumnColor(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, SDL_Color color, const char* formatted_text, ...);
FC_Rect FC_DrawColumnEffect(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_Effect effect, const char* formatted_text, ...);
// Getters
FC_FilterEnum FC_GetFilterMode(FC_Font* font);
Uint16 FC_GetLineHeight(FC_Font* font);
Uint16 FC_GetHeight(FC_Font* font, const char* formatted_text, ...);
Uint16 FC_GetWidth(FC_Font* font, const char* formatted_text, ...);
// Returns a 1-pixel wide box in front of the character in the given position (index)
FC_Rect FC_GetCharacterOffset(FC_Font* font, Uint16 position_index, int column_width, const char* formatted_text, ...);
Uint16 FC_GetColumnHeight(FC_Font* font, Uint16 width, const char* formatted_text, ...);
int FC_GetAscent(FC_Font* font, const char* formatted_text, ...);
int FC_GetDescent(FC_Font* font, const char* formatted_text, ...);
int FC_GetBaseline(FC_Font* font);
int FC_GetSpacing(FC_Font* font);
int FC_GetLineSpacing(FC_Font* font);
Uint16 FC_GetMaxWidth(FC_Font* font);
SDL_Color FC_GetDefaultColor(FC_Font* font);
FC_Rect FC_GetBounds(FC_Font* font, float x, float y, FC_AlignEnum align, FC_Scale scale, const char* formatted_text, ...);
Uint8 FC_InRect(float x, float y, FC_Rect input_rect);
// Given an offset (x,y) from the text draw position (the upper-left corner), returns the character position (UTF-8 index)
Uint16 FC_GetPositionFromOffset(FC_Font* font, float x, float y, int column_width, FC_AlignEnum align, const char* formatted_text, ...);
// Returns the number of characters in the new wrapped text written into `result`.
int FC_GetWrappedText(FC_Font* font, char* result, int max_result_size, Uint16 width, const char* formatted_text, ...);
// Setters
void FC_SetFilterMode(FC_Font* font, FC_FilterEnum filter);
void FC_SetSpacing(FC_Font* font, int LetterSpacing);
void FC_SetLineSpacing(FC_Font* font, int LineSpacing);
void FC_SetDefaultColor(FC_Font* font, SDL_Color color);
#ifdef __cplusplus
}
#endif
#endif

295
source/gui/GuiButton.cpp Normal file
View File

@ -0,0 +1,295 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <iostream>
#include <gui/GuiButton.h>
#include <gui/GuiController.h>
/**
* Constructor for the GuiButton class.
*/
GuiButton::GuiButton(float w, float h) {
width = w;
height = h;
image = nullptr;
imageOver = nullptr;
imageHold = nullptr;
imageClick = nullptr;
icon = nullptr;
iconOver = nullptr;
for (int32_t i = 0; i < 4; i++) {
label[i] = nullptr;
labelOver[i] = nullptr;
labelHold[i] = nullptr;
labelClick[i] = nullptr;
}
for (auto &i : trigger) {
i = nullptr;
}
soundOver = nullptr;
soundHold = nullptr;
soundClick = nullptr;
clickedTrigger = nullptr;
heldTrigger = nullptr;
selectable = true;
holdable = false;
clickable = true;
}
/**
* Destructor for the GuiButton class.
*/
GuiButton::~GuiButton() = default;
void GuiButton::setImage(GuiImage *img) {
image = img;
if (img) { img->setParent(this); }
}
void GuiButton::setImageOver(GuiImage *img) {
imageOver = img;
if (img) { img->setParent(this); }
}
void GuiButton::setImageHold(GuiImage *img) {
imageHold = img;
if (img) { img->setParent(this); }
}
void GuiButton::setImageClick(GuiImage *img) {
imageClick = img;
if (img) { img->setParent(this); }
}
void GuiButton::setIcon(GuiImage *img) {
icon = img;
if (img) { img->setParent(this); }
}
void GuiButton::setIconOver(GuiImage *img) {
iconOver = img;
if (img) { img->setParent(this); }
}
void GuiButton::setLabel(GuiText *txt, int32_t n) {
label[n] = txt;
if (txt) { txt->setParent(this); }
}
void GuiButton::setLabelOver(GuiText *txt, int32_t n) {
labelOver[n] = txt;
if (txt) { txt->setParent(this); }
}
void GuiButton::setLabelHold(GuiText *txt, int32_t n) {
labelHold[n] = txt;
if (txt) { txt->setParent(this); }
}
void GuiButton::setLabelClick(GuiText *txt, int32_t n) {
labelClick[n] = txt;
if (txt) { txt->setParent(this); }
}
void GuiButton::setSoundOver(GuiSound *snd) {
soundOver = snd;
}
void GuiButton::setSoundHold(GuiSound *snd) {
soundHold = snd;
}
void GuiButton::setSoundClick(GuiSound *snd) {
soundClick = snd;
}
void GuiButton::setTrigger(GuiTrigger *t, int32_t idx) {
if (idx >= 0 && idx < iMaxGuiTriggers) {
trigger[idx] = t;
} else {
for (auto &i : trigger) {
if (!i) {
i = t;
break;
}
}
}
}
void GuiButton::resetState() {
clickedTrigger = nullptr;
heldTrigger = nullptr;
GuiElement::resetState();
}
/**
* Draw the button on screen
*/
void GuiButton::draw(Renderer *v) {
if (!this->isVisible()) {
return;
}
// draw image
if ((isDrawOverOnlyWhenSelected() && (isStateSet(STATE_SELECTED) && imageOver)) ||
(!isDrawOverOnlyWhenSelected() && (isStateSet(STATE_OVER | STATE_SELECTED | STATE_CLICKED | STATE_HELD) && imageOver))) {
imageOver->draw(v);
} else if (image) {
image->draw(v);
}
if ((isDrawOverOnlyWhenSelected() && (isStateSet(STATE_SELECTED) && iconOver)) ||
(!isDrawOverOnlyWhenSelected() && (isStateSet(STATE_OVER | STATE_SELECTED | STATE_CLICKED | STATE_HELD) && iconOver))) {
iconOver->draw(v);
} else if (icon) {
icon->draw(v);
}
// draw text
for (int32_t i = 0; i < 4; i++) {
if (isStateSet(STATE_OVER | STATE_SELECTED | STATE_CLICKED | STATE_HELD) && labelOver[i]) {
labelOver[i]->draw(v);
} else if (label[i]) {
label[i]->draw(v);
}
}
}
void GuiButton::update(GuiController *c) {
if (!c || isStateSet(STATE_DISABLED | STATE_HIDDEN | STATE_DISABLE_INPUT, c->chanIdx)) {
return;
} else if (parentElement && (parentElement->isStateSet(STATE_DISABLED | STATE_HIDDEN | STATE_DISABLE_INPUT, c->chanIdx))) {
return;
}
if (selectable) {
if (c->data.validPointer && this->isInside(c->data.x, c->data.y)) {
if (!isStateSet(STATE_OVER, c->chanIdx)) {
setState(STATE_OVER, c->chanIdx);
//if(this->isRumbleActive())
// this->rumble(t->chan);
if (soundOver) {
soundOver->Play();
}
if (effectsOver && !effects) {
// initiate effects
effects = effectsOver;
effectAmount = effectAmountOver;
effectTarget = effectTargetOver;
}
pointedOn(this, c);
}
} else if (isStateSet(STATE_OVER, c->chanIdx)) {
this->clearState(STATE_OVER, c->chanIdx);
pointedOff(this, c);
if (effectTarget == effectTargetOver && effectAmount == effectAmountOver) {
// initiate effects (in reverse)
effects = effectsOver;
effectAmount = -effectAmountOver;
effectTarget = 100;
}
}
}
for (auto & i : trigger) {
if (!i) {
continue;
}
// button triggers
if (clickable) {
int32_t isClicked = i->clicked(c);
if (!clickedTrigger && (isClicked != GuiTrigger::CLICKED_NONE)
&& (i->isClickEverywhere() || (isStateSet(STATE_SELECTED | STATE_OVER, c->chanIdx) && i->isSelectionClickEverywhere()) || this->isInside(c->data.x, c->data.y))) {
if (soundClick) {
soundClick->Play();
}
clickedTrigger = i;
if (!isStateSet(STATE_CLICKED, c->chanIdx)) {
if (isClicked == GuiTrigger::CLICKED_TOUCH) {
setState(STATE_CLICKED_TOUCH, c->chanIdx);
} else {
setState(STATE_CLICKED, c->chanIdx);
}
}
clicked(this, c, i);
} else if ((isStateSet(STATE_CLICKED, c->chanIdx) || isStateSet(STATE_CLICKED_TOUCH, c->chanIdx)) && (clickedTrigger == i) && !isStateSet(STATE_HELD, c->chanIdx) && !i->held(c) &&
((isClicked == GuiTrigger::CLICKED_NONE) || i->released(c))) {
if ((isStateSet(STATE_CLICKED_TOUCH, c->chanIdx) && this->isInside(c->data.x, c->data.y)) || (isStateSet(STATE_CLICKED, c->chanIdx))) {
clickedTrigger = nullptr;
clearState(STATE_CLICKED, c->chanIdx);
released(this, c, i);
}
}
}
if (holdable) {
bool isHeld = i->held(c);
if ((!heldTrigger || heldTrigger == i) && isHeld
&& (i->isHoldEverywhere() || (isStateSet(STATE_SELECTED | STATE_OVER, c->chanIdx) && i->isSelectionClickEverywhere()) || this->isInside(c->data.x, c->data.y))) {
heldTrigger = i;
if (!isStateSet(STATE_HELD, c->chanIdx)) {
setState(STATE_HELD, c->chanIdx);
}
held(this, c, i);
} else if (isStateSet(STATE_HELD, c->chanIdx) && (heldTrigger == i) && (!isHeld || i->released(c))) {
//! click is removed at this point and converted to held
if (clickedTrigger == i) {
clickedTrigger = nullptr;
clearState(STATE_CLICKED, c->chanIdx);
}
heldTrigger = nullptr;
clearState(STATE_HELD, c->chanIdx);
released(this, c, i);
}
}
}
}
void GuiButton::process() {
GuiElement::process();
if(image) { image->process(); }
if(imageOver) { imageOver->process(); }
if(imageHold) { imageHold->process(); }
if(imageClick) { imageClick->process(); }
if(icon) { icon->process(); }
if(iconOver) { iconOver->process(); }
if(soundOver) { soundOver->process(); }
if(soundHold) { soundHold->process(); }
if(soundClick) { soundClick->process(); }
for(int i = 0;i<4;i++){
if(label[i]) { label[i]->process(); }
if(labelOver[i]) { labelOver[i]->process(); }
if(labelHold[i]) { labelHold[i]->process(); }
if(labelClick[i]) { labelClick[i]->process(); }
}
}

290
source/gui/GuiElement.cpp Normal file
View File

@ -0,0 +1,290 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <gui/GuiElement.h>
//! TODO remove this!
static int32_t screenwidth = 1280;
static int32_t screenheight = 720;
/**
* Constructor for the Object class.
*/
GuiElement::GuiElement() {
xoffset = 0.0f;
yoffset = 0.0f;
zoffset = 0.0f;
width = 0.0f;
height = 0.0f;
alpha = 1.0f;
scaleX = 1.0f;
scaleY = 1.0f;
scaleZ = 1.0f;
for (unsigned int & i : state) {
i = STATE_DEFAULT;
}
stateChan = -1;
parentElement = nullptr;
rumble = true;
selectable = false;
clickable = false;
holdable = false;
drawOverOnlyWhenSelected = false;
visible = true;
yoffsetDyn = 0;
xoffsetDyn = 0;
alphaDyn = -1;
scaleDyn = 1;
effects = EFFECT_NONE;
effectAmount = 0;
effectTarget = 0;
effectsOver = EFFECT_NONE;
effectAmountOver = 0;
effectTargetOver = 0;
angle = 0.0f;
// default alignment - align to top left
alignment = (ALIGN_TOP_LEFT);
}
/**
* Get the left position of the GuiElement.
* @see SetLeft()
* @return Left position in pixel.
*/
float GuiElement::getLeft() {
float pWidth = 0;
float pLeft = 0;
float pScaleX = 1.0f;
if (parentElement) {
pWidth = parentElement->getWidth();
pLeft = parentElement->getLeft();
pScaleX = parentElement->getScaleX();
}
pLeft += xoffsetDyn;
float x = pLeft;
//! TODO: the conversion from int to float and back to int is bad for performance, change that
if (alignment & ALIGN_CENTER) {
x = pLeft + pWidth * 0.5f * pScaleX - width * 0.5f * getScaleX();
} else if (alignment & ALIGN_RIGHT) {
x = pLeft + pWidth * pScaleX - width * getScaleX();
}
return x + xoffset;
}
/**
* Get the top position of the GuiElement.
* @see SetTop()
* @return Top position in pixel.
*/
float GuiElement::getTop() {
float pHeight = 0;
float pTop = 0;
float pScaleY = 1.0f;
if (parentElement) {
pHeight = parentElement->getHeight();
pTop = parentElement->getTop();
pScaleY = parentElement->getScaleY();
}
pTop += yoffsetDyn;
float y = pTop;
//! TODO: the conversion from int to float and back to int is bad for performance, change that
if (alignment & ALIGN_MIDDLE) {
y = pTop + pHeight * 0.5f * pScaleY - getHeight() * 0.5f * getScaleY();
} else if (alignment & ALIGN_BOTTOM) {
y = pTop + pHeight * pScaleY - getHeight() * getScaleY();
}
return y + yoffset;
}
void GuiElement::setEffect(uint32_t eff, int32_t amount, int32_t target) {
if (eff & EFFECT_SLIDE_IN) {
// these calculations overcompensate a little
if (eff & EFFECT_SLIDE_TOP) {
if (eff & EFFECT_SLIDE_FROM) {
yoffsetDyn = (int32_t) -getHeight() * scaleY;
} else {
yoffsetDyn = -screenheight;
}
} else if (eff & EFFECT_SLIDE_LEFT) {
if (eff & EFFECT_SLIDE_FROM) {
xoffsetDyn = (int32_t) -getWidth() * scaleX;
} else {
xoffsetDyn = -screenwidth;
}
} else if (eff & EFFECT_SLIDE_BOTTOM) {
if (eff & EFFECT_SLIDE_FROM) {
yoffsetDyn = (int32_t) getHeight() * scaleY;
} else {
yoffsetDyn = screenheight;
}
} else if (eff & EFFECT_SLIDE_RIGHT) {
if (eff & EFFECT_SLIDE_FROM) {
xoffsetDyn = (int32_t) getWidth() * scaleX;
} else {
xoffsetDyn = screenwidth;
}
}
}
if ((eff & EFFECT_FADE) && amount > 0) {
alphaDyn = 0;
} else if ((eff & EFFECT_FADE) && amount < 0) {
alphaDyn = alpha;
}
effects |= eff;
effectAmount = amount;
effectTarget = target;
}
//!Sets an effect to be enabled on wiimote cursor over
//!\param e Effect to enable
//!\param a Amount of the effect (usage varies on effect)
//!\param t Target amount of the effect (usage varies on effect)
void GuiElement::setEffectOnOver(uint32_t e, int32_t a, int32_t t) {
effectsOver |= e;
effectAmountOver = a;
effectTargetOver = t;
}
void GuiElement::resetEffects() {
yoffsetDyn = 0;
xoffsetDyn = 0;
alphaDyn = -1;
scaleDyn = 1;
effects = EFFECT_NONE;
effectAmount = 0;
effectTarget = 0;
effectsOver = EFFECT_NONE;
effectAmountOver = 0;
effectTargetOver = 0;
}
void GuiElement::updateEffects() {
if (!this->isVisible() && parentElement) {
return;
}
if (effects & (EFFECT_SLIDE_IN | EFFECT_SLIDE_OUT | EFFECT_SLIDE_FROM)) {
if (effects & EFFECT_SLIDE_IN) {
if (effects & EFFECT_SLIDE_LEFT) {
xoffsetDyn += effectAmount;
if (xoffsetDyn >= 0) {
xoffsetDyn = 0;
effects = 0;
effectFinished(this);
}
} else if (effects & EFFECT_SLIDE_RIGHT) {
xoffsetDyn -= effectAmount;
if (xoffsetDyn <= 0) {
xoffsetDyn = 0;
effects = 0;
effectFinished(this);
}
} else if (effects & EFFECT_SLIDE_TOP) {
yoffsetDyn += effectAmount;
if (yoffsetDyn >= 0) {
yoffsetDyn = 0;
effects = 0;
effectFinished(this);
}
} else if (effects & EFFECT_SLIDE_BOTTOM) {
yoffsetDyn -= effectAmount;
if (yoffsetDyn <= 0) {
yoffsetDyn = 0;
effects = 0;
effectFinished(this);
}
}
} else {
if (effects & EFFECT_SLIDE_LEFT) {
xoffsetDyn -= effectAmount;
if (xoffsetDyn <= -screenwidth) {
effects = 0; // shut off effect
effectFinished(this);
} else if ((effects & EFFECT_SLIDE_FROM) && xoffsetDyn <= -getWidth()) {
effects = 0; // shut off effect
effectFinished(this);
}
} else if (effects & EFFECT_SLIDE_RIGHT) {
xoffsetDyn += effectAmount;
if (xoffsetDyn >= screenwidth) {
effects = 0; // shut off effect
effectFinished(this);
} else if ((effects & EFFECT_SLIDE_FROM) && xoffsetDyn >= getWidth() * scaleX) {
effects = 0; // shut off effect
effectFinished(this);
}
} else if (effects & EFFECT_SLIDE_TOP) {
yoffsetDyn -= effectAmount;
if (yoffsetDyn <= -screenheight) {
effects = 0; // shut off effect
effectFinished(this);
} else if ((effects & EFFECT_SLIDE_FROM) && yoffsetDyn <= -getHeight()) {
effects = 0; // shut off effect
effectFinished(this);
}
} else if (effects & EFFECT_SLIDE_BOTTOM) {
yoffsetDyn += effectAmount;
if (yoffsetDyn >= screenheight) {
effects = 0; // shut off effect
effectFinished(this);
} else if ((effects & EFFECT_SLIDE_FROM) && yoffsetDyn >= getHeight()) {
effects = 0; // shut off effect
effectFinished(this);
}
}
}
} else if (effects & EFFECT_FADE) {
alphaDyn += effectAmount * (1.0f / 255.0f);
if (effectAmount < 0 && alphaDyn <= 0) {
alphaDyn = 0;
effects = 0; // shut off effect
effectFinished(this);
} else if (effectAmount > 0 && alphaDyn >= alpha) {
alphaDyn = alpha;
effects = 0; // shut off effect
effectFinished(this);
}
} else if (effects & EFFECT_SCALE) {
scaleDyn += effectAmount * 0.01f;
if ((effectAmount < 0 && scaleDyn <= (effectTarget * 0.01f))
|| (effectAmount > 0 && scaleDyn >= (effectTarget * 0.01f))) {
scaleDyn = effectTarget * 0.01f;
effects = 0; // shut off effect
effectFinished(this);
}
}
}

226
source/gui/GuiFrame.cpp Normal file
View File

@ -0,0 +1,226 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <gui/GuiFrame.h>
GuiFrame::GuiFrame(GuiFrame *p) {
parent = p;
width = 0;
height = 0;
dim = false;
if (parent) {
parent->append(this);
}
}
GuiFrame::GuiFrame(float w, float h, GuiFrame *p) {
parent = p;
width = w;
height = h;
dim = false;
if (parent) {
parent->append(this);
}
}
GuiFrame::~GuiFrame() {
closing(this);
if (parent) {
parent->remove(this);
}
}
void GuiFrame::append(GuiElement *e) {
if (e == nullptr) {
return;
}
remove(e);
mutex.lock();
elements.push_back(e);
e->setParent(this);
mutex.unlock();
}
void GuiFrame::insert(GuiElement *e, uint32_t index) {
if (e == nullptr || (index >= elements.size())) {
return;
}
remove(e);
mutex.lock();
elements.insert(elements.begin() + index, e);
e->setParent(this);
mutex.unlock();
}
void GuiFrame::remove(GuiElement *e) {
if (e == NULL) {
return;
}
mutex.lock();
for (uint32_t i = 0; i < elements.size(); ++i) {
if (e == elements[i]) {
elements.erase(elements.begin() + i);
break;
}
}
mutex.unlock();
}
void GuiFrame::removeAll() {
mutex.lock();
elements.clear();
mutex.unlock();
}
GuiElement *GuiFrame::getGuiElementAt(uint32_t index) const {
if (index >= elements.size()) {
return nullptr;
}
return elements[index];
}
uint32_t GuiFrame::getSize() {
return elements.size();
}
void GuiFrame::resetState() {
GuiElement::resetState();
mutex.lock();
for (auto & element : elements) {
element->resetState();
}
mutex.unlock();
}
void GuiFrame::setState(uint32_t s, int32_t c) {
GuiElement::setState(s, c);
mutex.lock();
for (uint32_t i = 0; i < elements.size(); ++i) {
elements[i]->setState(s, c);
}
mutex.unlock();
}
void GuiFrame::clearState(uint32_t s, int32_t c) {
GuiElement::clearState(s, c);
mutex.lock();
for (uint32_t i = 0; i < elements.size(); ++i) {
elements[i]->clearState(s, c);
}
mutex.unlock();
}
void GuiFrame::setVisible(bool v) {
visible = v;
mutex.lock();
for (auto & element : elements) {
element->setVisible(v);
}
mutex.unlock();
}
int32_t GuiFrame::getSelected() {
// find selected element
int32_t found = -1;
mutex.lock();
for (uint32_t i = 0; i < elements.size(); ++i) {
if (elements[i]->isStateSet(STATE_SELECTED | STATE_OVER)) {
found = i;
break;
}
}
mutex.unlock();
return found;
}
void GuiFrame::draw(Renderer *v) {
if (!this->isVisible() && parentElement) {
return;
}
if (parentElement && dim) {
//GXColor dimColor = (GXColor){0, 0, 0, 0x70};
//Menu_DrawRectangle(0, 0, GetZPosition(), screenwidth,screenheight, &dimColor, false, true);
}
mutex.lock();
//! render appended items next frame but allow stop of render if size is reached
uint32_t size = elements.size();
for (uint32_t i = 0; i < size && i < elements.size(); ++i) {
elements[i]->draw(v);
}
mutex.unlock();
}
void GuiFrame::updateEffects() {
if (!this->isVisible() && parentElement) {
return;
}
GuiElement::updateEffects();
mutex.lock();
//! render appended items next frame but allow stop of render if size is reached
uint32_t size = elements.size();
for (uint32_t i = 0; i < size && i < elements.size(); ++i) {
elements[i]->updateEffects();
}
mutex.unlock();
}
void GuiFrame::process() {
if (!this->isVisible() && parentElement) {
return;
}
GuiElement::process();
mutex.lock();
//! render appended items next frame but allow stop of render if size is reached
uint32_t size = elements.size();
for (uint32_t i = 0; i < size && i < elements.size(); ++i) {
elements[i]->process();
}
mutex.unlock();
}
void GuiFrame::update(GuiController *c) {
if (isStateSet(STATE_DISABLED) && parentElement) {
return;
}
mutex.lock();
//! update appended items next frame
uint32_t size = elements.size();
for (uint32_t i = 0; i < size && i < elements.size(); ++i) {
elements[i]->update(c);
}
mutex.unlock();
}

66
source/gui/GuiImage.cpp Normal file
View File

@ -0,0 +1,66 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <SDL2/SDL_image.h>
#include <gui/GuiImage.h>
#include <gui/system/libgui_log.h>
GuiImage::GuiImage(GuiTextureData *texture) {
setTexture(texture);
}
GuiImage::GuiImage(SDL_Color color, float width, float height) {
this->color = color;
this->setSize(width, height);
}
GuiImage::~GuiImage() {
if (this->texture && freeTextureData) {
delete this->texture;
}
}
void GuiImage::draw(Renderer *renderer) {
if (!this->isVisible()) {
return;
}
SDL_Rect rect;
rect.x = (int) getLeft();
rect.y = (int) getTop();
rect.w = (int) (getScaleX() * getWidth());
rect.h = (int) (getScaleY() * getHeight());
if (texture) {
texture->draw(renderer, rect, getAngle());
} else {
SDL_SetRenderDrawColor(renderer->getRenderer(), color.r, color.g, color.b, color.a);
SDL_RenderFillRect(renderer->getRenderer(), &rect);
if(getAngle() != 0.0f){
LG_Log("Drawing a rotated rect is not supported yet");
}
}
}
void GuiImage::setTexture(GuiTextureData *tex) {
if (tex) {
if(this->texture && freeTextureData){
delete this->texture;
}
this->texture = tex;
this->setSize(tex->getWidth(), tex->getHeight());
}
}

79
source/gui/GuiSound.cpp Normal file
View File

@ -0,0 +1,79 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <gui/GuiSound.h>
GuiSound::GuiSound(void *buffer, uint32_t filesize, bool freeSrc) {
SDL_RWops *rw = SDL_RWFromMem(buffer, filesize);
music = Mix_LoadWAV_RW(rw, freeSrc);
}
GuiSound::GuiSound(const char *filepath) {
Load(filepath);
}
GuiSound::~GuiSound() {
if (music) {
Mix_FreeChunk(music);
music = nullptr;
}
}
bool GuiSound::Load(const char *filepath) {
music = Mix_LoadWAV(filepath);
return music != nullptr;
}
void GuiSound::Play() {
if (music) {
playedOn = Mix_PlayChannel(-1, music, loops);
}
}
void GuiSound::Stop() const {
Pause();
}
void GuiSound::Pause() const {
if (playedOn != -1) {
Mix_HaltChannel(playedOn);
}
}
void GuiSound::Resume() {
Play();
}
bool GuiSound::IsPlaying() const {
if (playedOn == -1) {
return false;
}
return Mix_Playing(playedOn);
}
void GuiSound::SetVolume(uint32_t vol) const {
if (music) { Mix_VolumeChunk(music, vol); }
}
void GuiSound::SetLoop(bool l) {
// < 0 == infinitive loop
loops = l ? -1 : 1;
}
void GuiSound::Rewind() const {
// TODO: how to rewind?
Stop();
}

97
source/gui/GuiText.cpp Normal file
View File

@ -0,0 +1,97 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <cstdarg>
#include <SDL2/SDL_surface.h>
#include <gui/GuiText.h>
#include <gui/system/libgui_log.h>
/**
* Constructor for the GuiText class.
*/
GuiText::GuiText(const std::string& text, SDL_Color c, FC_Font* gFont) {
this->text = text;
this->color = c;
this->fc_font = gFont;
this->doUpdateTexture = true;
this->texture.setParent(this);
}
GuiText::~GuiText() {
delete textureData;
}
void GuiText::draw(Renderer *renderer) {
if (!this->isVisible()) {
return;
}
updateTexture(renderer);
texture.draw(renderer);
}
void GuiText::process() {
GuiElement::process();
}
void GuiText::setMaxWidth(float width) {
this->maxWidth = width;
// Rebuild the texture cache on next draw
doUpdateTexture = true;
}
void GuiText::updateSize() {
auto height = FC_GetColumnHeight(fc_font, maxWidth, text.c_str());
auto width = FC_GetWidth(fc_font, text.c_str());
width = width > maxWidth ? maxWidth : width;
this->setSize(width, height);
}
void GuiText::updateTexture(Renderer *renderer) {
if(doUpdateTexture) {
updateSize();
int tex_width = width == 0 ? 1 : (int) width;
int tex_height = height == 0 ? 1 : (int)height;
SDL_Texture *temp = SDL_CreateTexture(renderer->getRenderer(), renderer->getPixelFormat(), SDL_TEXTUREACCESS_TARGET, tex_width, tex_height);
if (temp) {
texture.setTexture(nullptr);
delete textureData;
textureData = new GuiTextureData(temp);
textureData->setBlendMode(SDL_BLENDMODE_BLEND);
texture.setTexture(textureData);
// Set render target to texture
SDL_SetRenderTarget(renderer->getRenderer(), temp);
// Clear texture.
SDL_SetRenderDrawColor(renderer->getRenderer(), 0, 0, 0, 0);
SDL_RenderClear(renderer->getRenderer());
// Draw text to texture
FC_DrawColumn(fc_font, renderer->getRenderer(), 0, 0, maxWidth, text.c_str());
// Restore render target
SDL_SetRenderTarget(renderer->getRenderer(), nullptr);
} else {
LG_Log("Failed to create texture");
}
doUpdateTexture = false;
}
}

View File

@ -0,0 +1,93 @@
#include <SDL2/SDL_image.h>
#include <gui/GuiTextureData.h>
#include <gui/system/SDLSystem.h>
#include <gui/system/libgui_log.h>
GuiTextureData::GuiTextureData(const std::string& path) {
SDL_Surface *surface = IMG_Load_RW(SDL_RWFromFile(path.c_str(), "rb"), 1);
loadSurface(surface);
}
GuiTextureData::GuiTextureData(void *buffer, const uint32_t filesize, bool freesrc) {
SDL_RWops *rw = SDL_RWFromMem(buffer, filesize);
SDL_Surface *surface = IMG_Load_RW(rw, freesrc);
loadSurface(surface);
}
GuiTextureData::GuiTextureData(SDL_Texture *texture) {
if (this->texture) {
SDL_DestroyTexture(this->texture);
this->texture = nullptr;
}
this->texture = texture;
int w, h;
SDL_QueryTexture(this->texture, nullptr, nullptr, &w, &h);
this->width = w;
this->height = h;
}
void GuiTextureData::loadSurface(SDL_Surface *pSurface) {
if(!pSurface){
return;
}
cleanUp();
imgSurface = pSurface;
this->width = imgSurface->w;
this->height = imgSurface->h;
}
void GuiTextureData::cleanUp() {
if (imgSurface) {
SDL_FreeSurface(imgSurface);
imgSurface = nullptr;
}
if (texture) {
SDL_DestroyTexture(texture);
texture = nullptr;
}
}
/**
* Destructor for the GuiImage class.
*/
GuiTextureData::~GuiTextureData() {
cleanUp();
}
void GuiTextureData::draw(Renderer *renderer, const SDL_Rect& dest, float angle) {
if (texture == nullptr && imgSurface) {
texture = SDL_CreateTextureFromSurface(renderer->getRenderer(), imgSurface);
}
if (!texture) {
LG_Log("no texture!");
return;
}
// copy the texture to the rendering context
SDL_BlendMode mode;
SDL_GetRenderDrawBlendMode(renderer->getRenderer(), &mode);
// adjust blend mode
if(blendMode != mode){
SDL_SetRenderDrawBlendMode(renderer->getRenderer(), blendMode);
}
if (angle == 0) {
SDL_RenderCopy(renderer->getRenderer(), texture, nullptr, &dest);
} else {
SDL_RenderCopyEx(renderer->getRenderer(), texture, nullptr, &dest, angle, nullptr, SDL_FLIP_NONE);
}
if(blendMode != mode){
SDL_SetRenderDrawBlendMode(renderer->getRenderer(), mode);
}
}
int GuiTextureData::setBlendMode(SDL_BlendMode blendMode) {
this->blendMode = blendMode;
if(texture){ return SDL_SetTextureBlendMode(texture, blendMode); }
return SDL_BLENDMODE_INVALID;
}

142
source/gui/GuiTrigger.cpp Normal file
View File

@ -0,0 +1,142 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <gui/GuiController.h>
/**
* Constructor for the GuiTrigger class.
*/
GuiTrigger::GuiTrigger()
: chan(CHANNEL_ALL), btns(BUTTON_NONE), bClickEverywhere(false), bHoldEverywhere(false), bSelectionClickEverywhere(false), bLastTouched(false) {
}
GuiTrigger::GuiTrigger(uint32_t ch, uint32_t btn, bool clickEverywhere, bool holdEverywhere, bool selectionClickEverywhere)
: chan(ch), btns(btn), bClickEverywhere(clickEverywhere), bHoldEverywhere(holdEverywhere), bSelectionClickEverywhere(selectionClickEverywhere), bLastTouched(false) {
}
/**
* Destructor for the GuiTrigger class.
*/
GuiTrigger::~GuiTrigger() = default;
/**
* Sets a simple trigger. Requires:
* - Element is selected
* - Trigger button is pressed
*/
void GuiTrigger::setTrigger(uint32_t ch, uint32_t btn) {
chan = ch;
btns = btn;
}
bool GuiTrigger::left(const GuiController *controller) const {
if ((controller->chan & chan) == 0) {
return false;
}
if ((controller->data.buttons_h | controller->data.buttons_d) & (BUTTON_LEFT | STICK_L_LEFT)) {
return true;
}
return false;
}
bool GuiTrigger::right(const GuiController *controller) const {
if ((controller->chan & chan) == 0) {
return false;
}
if ((controller->data.buttons_h | controller->data.buttons_d) & (BUTTON_RIGHT | STICK_L_RIGHT)) {
return true;
}
return false;
}
bool GuiTrigger::up(const GuiController *controller) const {
if ((controller->chan & chan) == 0) {
return false;
}
if ((controller->data.buttons_h | controller->data.buttons_d) & (BUTTON_UP | STICK_L_UP)) {
return true;
}
return false;
}
bool GuiTrigger::down(const GuiController *controller) const {
if ((controller->chan & chan) == 0) {
return false;
}
if ((controller->data.buttons_h | controller->data.buttons_d) & (BUTTON_DOWN | STICK_L_DOWN)) {
return true;
}
return false;
}
int32_t GuiTrigger::clicked(const GuiController *controller) const {
if ((controller->chan & chan) == 0) {
return CLICKED_NONE;
}
int32_t bResult = CLICKED_NONE;
if (controller->data.touched && controller->data.validPointer && (btns & TOUCHED) && !controller->lastData.touched) {
bResult = CLICKED_TOUCH;
}
if (controller->data.buttons_d & btns) {
bResult = CLICKED_BUTTON;
}
return bResult;
}
bool GuiTrigger::held(const GuiController *controller) const {
if ((controller->chan & chan) == 0) {
return false;
}
bool bResult = false;
if (controller->data.touched && (btns & TOUCHED) && controller->data.validPointer && controller->lastData.touched && controller->lastData.validPointer) {
bResult = true;
}
if (controller->data.buttons_h & btns) {
bResult = true;
}
return bResult;
}
bool GuiTrigger::released(const GuiController *controller) const {
if ((controller->chan & chan) == 0) {
return false;
}
if (clicked(controller) || held(controller)) {
return false;
}
bool bResult = false;
if (!controller->data.touched && (btns & TOUCHED) && controller->lastData.touched && controller->lastData.validPointer) {
bResult = true;
}
if (controller->data.buttons_r & btns) {
bResult = true;
}
return bResult;
}

View File

@ -0,0 +1,104 @@
#include <functional>
#include <gui/input/ControllerManager.h>
#include <gui/input/SDLControllerWiiUGamepad.h>
#include <gui/input/SDLControllerXboxOne.h>
#include <gui/input/SDLControllerWiiUProContoller.h>
#include <gui/input/SDLControllerJoystick.h>
GuiTrigger::eChannels ControllerManager::increaseChannel(GuiTrigger::eChannels channel) {
switch (channel) {
case GuiTrigger::CHANNEL_1:
return GuiTrigger::CHANNEL_2;
case GuiTrigger::CHANNEL_2:
return GuiTrigger::CHANNEL_3;
case GuiTrigger::CHANNEL_3:
return GuiTrigger::CHANNEL_4;
case GuiTrigger::CHANNEL_4:
return GuiTrigger::CHANNEL_5;
case GuiTrigger::CHANNEL_5:
case GuiTrigger::CHANNEL_ALL:
return GuiTrigger::CHANNEL_ALL;
}
return GuiTrigger::CHANNEL_ALL;
}
void ControllerManager::attachController(GuiTrigger::eChannels channel, SDLController *controller) {
controllerList[channel] = controller;
}
void ControllerManager::prepare() {
//! Read out inputs
for (auto const&[channel, controller] : controllerList) {
controller->before();
}
}
bool ControllerManager::attachJoystick(int32_t deviceId) {
auto joystick = SDL_JoystickOpen(deviceId);
if (joystick == nullptr) {
LG_Log("SDL_JoystickOpen failed: %s\n", SDL_GetError());
return false;
}
auto instanceId = SDL_JoystickInstanceID(joystick);
if (std::string("WiiU Gamepad") == SDL_JoystickName(joystick)) {
controllerList[GuiTrigger::CHANNEL_1] = new SDLControllerWiiUGamepad(GuiTrigger::CHANNEL_1);
joystickToChannel[instanceId] = GuiTrigger::CHANNEL_1;
} else {
bool successfully_added = false;
auto channel = GuiTrigger::CHANNEL_2;
while (channel != GuiTrigger::CHANNEL_ALL) {
if (controllerList.find(channel) == controllerList.end()) {
if (std::string(SDL_JoystickName(joystick)).find("Xbox") != std::string::npos
|| std::string(SDL_JoystickName(joystick)).find("X-Box") != std::string::npos) {
controllerList[channel] = new SDLControllerXboxOne(channel);
} else if (std::string(SDL_JoystickName(joystick)).find("WiiU Pro Controller") != std::string::npos) {
controllerList[channel] = new SDLControllerWiiUProContoller(channel);
} else {
controllerList[channel] = new SDLControllerJoystick(channel, instanceId);
}
joystickToChannel[instanceId] = channel;
successfully_added = true;
break;
}
channel = increaseChannel(channel);
}
if (!successfully_added) {
LG_Log("Failed to add joystick. Closing it now");
SDL_JoystickClose(joystick);
return false;
}
}
LG_Log("Added joystick %s", SDL_JoystickName(joystick));
return true;
}
void ControllerManager::detachJoystick(int32_t instanceId) {
auto channel = joystickToChannel[instanceId];
delete controllerList[channel];
controllerList.erase(channel);
joystickToChannel.erase(instanceId);
LG_Log("Removed joystick: %d", instanceId);
}
void ControllerManager::processEvent(SDL_JoystickID joystickId, int32_t channel, SDL_Event *e) {
if (joystickId != -1) {
if (joystickToChannel.find(joystickId) != joystickToChannel.end()) {
channel = joystickToChannel[joystickId];
}
}
if (channel != -1 && controllerList.count(static_cast<const GuiTrigger::eChannels>(channel)) > 0) {
controllerList[static_cast<GuiTrigger::eChannels>(channel)]->update(e, screenWidth, screenHeight);
}
}
void ControllerManager::finish() {
for (auto const&[joypad, controller] : controllerList) {
controller->after();
}
}
void ControllerManager::callPerController(std::function<void(GuiController*)> func) {
for (auto const&[joypad, controller] : controllerList) {
func(controller);
}
}

View File

@ -0,0 +1,84 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <gui/system/SDLSystem.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_mixer.h>
#include <SDL2/SDL_ttf.h>
#include <gui/system/libgui_log.h>
SDLSystem::SDLSystem() {
SDL_Init(SDL_INIT_EVERYTHING);
auto SDLFlags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC;
//Setup window
window = SDL_CreateWindow(nullptr, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, 0);
if (!window) {
LG_Log("Failed to create window");
return;
}
auto sdl_renderer = SDL_CreateRenderer(window, -1, SDLFlags);
if (!sdl_renderer) {
// DEBUG_FUNCTION_LINE("Failed to init sdl renderer");
return;
}
SDL_SetRenderTarget(sdl_renderer, nullptr);
this->renderer = new Renderer(sdl_renderer, SDL_GetWindowPixelFormat(window));
if (!renderer) {
LG_Log("Failed to init renderer");
return;
}
if (SDL_Init(SDL_INIT_AUDIO) != 0) {
LG_Log("SDL init error: %s\n", SDL_GetError());
return;
}
int flags = 0;
int result = 0;
if (flags != (result = Mix_Init(flags))) {
LG_Log("Could not initialize mixer (result: %d).\n", result);
LG_Log("Mix_Init: %s\n", Mix_GetError());
}
auto dev = Mix_OpenAudio(22050, AUDIO_S16SYS, 2, 640);
SDL_PauseAudioDevice(dev, 0);
TTF_Init();
}
SDLSystem::~SDLSystem() {
SDL_DestroyWindow(window);
delete renderer;
SDL_Quit();
}
float SDLSystem::getHeight() {
int h = 0;
SDL_GetWindowSize(window, nullptr, &h);
return h;
}
float SDLSystem::getWidth() {
int w = 0;
SDL_GetWindowSize(window, &w, nullptr);
return w;
}
Renderer *SDLSystem::getRenderer() {
return renderer;
}

File diff suppressed because it is too large Load Diff