Initial commit
This commit is contained in:
224
Makefile
Normal file
224
Makefile
Normal file
@@ -0,0 +1,224 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||
endif
|
||||
|
||||
TOPDIR ?= $(CURDIR)
|
||||
include $(DEVKITPRO)/libnx/switch_rules
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# 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 := swr-ini-tool
|
||||
BUILD := build.nx
|
||||
SOURCES := src
|
||||
RESOURCES := resources
|
||||
DATA := data
|
||||
INCLUDES :=
|
||||
APP_TITLE := SWR INI Tool
|
||||
APP_AUTHOR := NiklasCFW
|
||||
|
||||
ROMFS := $(BUILD)/romfs
|
||||
BOREALIS_PATH := lib/borealis
|
||||
BOREALIS_RESOURCES := romfs:/borealis/
|
||||
APP_RESOURCES := romfs:/
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# version control constants
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET_VERSION := 0.1.0
|
||||
APP_VERSION := $(TARGET_VERSION)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
|
||||
|
||||
CFLAGS := -g -Wall -O2 -ffunction-sections \
|
||||
$(ARCH) $(DEFINES)
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__SWITCH__ \
|
||||
-DAPP_TITLE="\"$(APP_TITLE)\"" \
|
||||
-DBOREALIS_RESOURCES="\"$(BOREALIS_RESOURCES)\"" \
|
||||
-DAPP_RESOURCES="\"$(APP_RESOURCES)\""
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -std=c++1z
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
LIBS := -lnx -lm
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(PORTLIBS) $(LIBNX)
|
||||
|
||||
include $(TOPDIR)/$(BOREALIS_PATH)/library/borealis.mk
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# 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 OUTPUT := $(CURDIR)/$(TARGET)
|
||||
export TOPDIR := $(CURDIR)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
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 := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
ifeq ($(strip $(CONFIG_JSON)),)
|
||||
jsons := $(wildcard *.json)
|
||||
ifneq (,$(findstring $(TARGET).json,$(jsons)))
|
||||
export APP_JSON := $(TOPDIR)/$(TARGET).json
|
||||
else
|
||||
ifneq (,$(findstring config.json,$(jsons)))
|
||||
export APP_JSON := $(TOPDIR)/config.json
|
||||
endif
|
||||
endif
|
||||
else
|
||||
export APP_JSON := $(TOPDIR)/$(CONFIG_JSON)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(ICON)),)
|
||||
icons := $(wildcard *.jpg)
|
||||
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
|
||||
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
|
||||
else
|
||||
ifneq (,$(findstring icon.jpg,$(icons)))
|
||||
export APP_ICON := $(TOPDIR)/icon.jpg
|
||||
endif
|
||||
endif
|
||||
else
|
||||
export APP_ICON := $(TOPDIR)/$(ICON)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(NO_ICON)),)
|
||||
export NROFLAGS += --icon=$(APP_ICON)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(NO_NACP)),)
|
||||
export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
|
||||
endif
|
||||
|
||||
ifneq ($(APP_TITLEID),)
|
||||
export NACPFLAGS += --titleid=$(APP_TITLEID)
|
||||
endif
|
||||
|
||||
ifneq ($(ROMFS),)
|
||||
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
||||
endif
|
||||
|
||||
.PHONY: $(BUILD) $(ROMFS) clean all
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
|
||||
$(ROMFS):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@echo Merging ROMFS...
|
||||
@cp -ruf $(CURDIR)/$(BOREALIS_PATH)/resources/. $(CURDIR)/$(ROMFS)/borealis/
|
||||
@cp -ruf $(CURDIR)/$(RESOURCES)/. $(CURDIR)/$(ROMFS)/
|
||||
|
||||
$(BUILD): $(ROMFS)
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@MSYS2_ARG_CONV_EXCL="-D;$(MSYS2_ARG_CONV_EXCL)" $(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
ifeq ($(strip $(APP_JSON)),)
|
||||
@rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).nso $(TARGET).elf
|
||||
else
|
||||
@rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf
|
||||
endif
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
.PHONY: all
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(APP_JSON)),)
|
||||
|
||||
all : $(OUTPUT).nro
|
||||
|
||||
ifeq ($(strip $(NO_NACP)),)
|
||||
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp
|
||||
else
|
||||
$(OUTPUT).nro : $(OUTPUT).elf
|
||||
endif
|
||||
|
||||
else
|
||||
|
||||
all : $(OUTPUT).nsp
|
||||
|
||||
$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm
|
||||
|
||||
$(OUTPUT).nso : $(OUTPUT).elf
|
||||
|
||||
endif
|
||||
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
$(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# you need a rule like this for each extension you use as binary data
|
||||
#---------------------------------------------------------------------------------
|
||||
%.bin.o %_bin.h : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
||||
21
lib/borealis/.clang-format
Normal file
21
lib/borealis/.clang-format
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
AccessModifierOffset: -2
|
||||
AlignConsecutiveAssignments: 'true'
|
||||
BasedOnStyle: WebKit
|
||||
BreakBeforeBraces: Allman
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^<borealis/.*\.hpp>'
|
||||
Priority: 2
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 1
|
||||
- Regex: '^<.*'
|
||||
Priority: 2
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
IndentCaseLabels: 'true'
|
||||
PointerAlignment: Left
|
||||
SortIncludes: 'true'
|
||||
Standard: Cpp11
|
||||
|
||||
...
|
||||
1
lib/borealis/.gitattributes
vendored
Normal file
1
lib/borealis/.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.glsl text eol=lf
|
||||
10
lib/borealis/.gitignore
vendored
Normal file
10
lib/borealis/.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
.*/
|
||||
build/
|
||||
build.nx/
|
||||
*~
|
||||
*.bak
|
||||
*.nro
|
||||
*.nacp
|
||||
*.elf
|
||||
.vscode
|
||||
builddir
|
||||
12
lib/borealis/.gitrepo
Normal file
12
lib/borealis/.gitrepo
Normal file
@@ -0,0 +1,12 @@
|
||||
; DO NOT EDIT (unless you know what you are doing)
|
||||
;
|
||||
; This subdirectory is a git "subrepo", and this file is maintained by the
|
||||
; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
|
||||
;
|
||||
[subrepo]
|
||||
remote = https://github.com/natinusala/borealis
|
||||
branch = master
|
||||
commit = 2ec4957301f702635feac64111dcd212d2a37ec6
|
||||
parent = ec9981362c84ff6d44bb574f311f1d994dc80d9c
|
||||
method = rebase
|
||||
cmdver = 0.4.0
|
||||
17
lib/borealis/COPYING
Normal file
17
lib/borealis/COPYING
Normal file
@@ -0,0 +1,17 @@
|
||||
Copyright (c) 2019 fincs
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
674
lib/borealis/LICENSE
Normal file
674
lib/borealis/LICENSE
Normal file
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
231
lib/borealis/Makefile
Normal file
231
lib/borealis/Makefile
Normal file
@@ -0,0 +1,231 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||
endif
|
||||
|
||||
TOPDIR ?= $(CURDIR)
|
||||
include $(DEVKITPRO)/libnx/switch_rules
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# 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
|
||||
# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
|
||||
#
|
||||
# NO_ICON: if set to anything, do not use icon.
|
||||
# NO_NACP: if set to anything, no .nacp file is generated.
|
||||
# APP_TITLE is the name of the app stored in the .nacp file (Optional)
|
||||
# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
|
||||
# APP_VERSION is the version of the app stored in the .nacp file (Optional)
|
||||
# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
|
||||
# ICON is the filename of the icon (.jpg), relative to the project folder.
|
||||
# If not set, it attempts to use one of the following (in this order):
|
||||
# - <Project name>.jpg
|
||||
# - icon.jpg
|
||||
# - <libnx folder>/default_icon.jpg
|
||||
#
|
||||
# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder.
|
||||
# If not set, it attempts to use one of the following (in this order):
|
||||
# - <Project name>.json
|
||||
# - config.json
|
||||
# If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead
|
||||
# of a homebrew executable (.nro). This is intended to be used for sysmodules.
|
||||
# NACP building is skipped as well.
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := borealis_example
|
||||
BUILD := build.nx
|
||||
SOURCES := example
|
||||
DATA := data
|
||||
ICON := resources/icon/borealis.jpg
|
||||
INCLUDES := example
|
||||
APP_TITLE := borealis example
|
||||
APP_AUTHOR := natinusala
|
||||
APP_VERSION := 1.0
|
||||
|
||||
ROMFS := resources
|
||||
BOREALIS_PATH := .
|
||||
BOREALIS_RESOURCES := romfs:/
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
|
||||
|
||||
CFLAGS := -g -Wall -O2 -ffunction-sections \
|
||||
$(ARCH) $(DEFINES)
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__SWITCH__ \
|
||||
-DBOREALIS_RESOURCES="\"$(BOREALIS_RESOURCES)\""
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-exceptions -std=c++1z -O2
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
LIBS := -lnx -lm
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(PORTLIBS) $(LIBNX)
|
||||
|
||||
include $(TOPDIR)/library/borealis.mk
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# 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 OUTPUT := $(CURDIR)/$(TARGET)
|
||||
export TOPDIR := $(CURDIR)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
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 := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
ifeq ($(strip $(CONFIG_JSON)),)
|
||||
jsons := $(wildcard *.json)
|
||||
ifneq (,$(findstring $(TARGET).json,$(jsons)))
|
||||
export APP_JSON := $(TOPDIR)/$(TARGET).json
|
||||
else
|
||||
ifneq (,$(findstring config.json,$(jsons)))
|
||||
export APP_JSON := $(TOPDIR)/config.json
|
||||
endif
|
||||
endif
|
||||
else
|
||||
export APP_JSON := $(TOPDIR)/$(CONFIG_JSON)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(ICON)),)
|
||||
icons := $(wildcard *.jpg)
|
||||
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
|
||||
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
|
||||
else
|
||||
ifneq (,$(findstring icon.jpg,$(icons)))
|
||||
export APP_ICON := $(TOPDIR)/icon.jpg
|
||||
endif
|
||||
endif
|
||||
else
|
||||
export APP_ICON := $(TOPDIR)/$(ICON)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(NO_ICON)),)
|
||||
export NROFLAGS += --icon=$(APP_ICON)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(NO_NACP)),)
|
||||
export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
|
||||
endif
|
||||
|
||||
ifneq ($(APP_TITLEID),)
|
||||
export NACPFLAGS += --titleid=$(APP_TITLEID)
|
||||
endif
|
||||
|
||||
ifneq ($(ROMFS),)
|
||||
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
||||
endif
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
ifeq ($(strip $(APP_JSON)),)
|
||||
@rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf
|
||||
else
|
||||
@rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf
|
||||
endif
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
.PHONY: all
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(APP_JSON)),)
|
||||
|
||||
all : $(OUTPUT).nro
|
||||
|
||||
ifeq ($(strip $(NO_NACP)),)
|
||||
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp
|
||||
else
|
||||
$(OUTPUT).nro : $(OUTPUT).elf
|
||||
endif
|
||||
|
||||
else
|
||||
|
||||
all : $(OUTPUT).nsp
|
||||
|
||||
$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm
|
||||
|
||||
$(OUTPUT).nso : $(OUTPUT).elf
|
||||
|
||||
endif
|
||||
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
$(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# you need a rule like this for each extension you use as binary data
|
||||
#---------------------------------------------------------------------------------
|
||||
%.bin.o %_bin.h : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
||||
65
lib/borealis/README.md
Normal file
65
lib/borealis/README.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# borealis
|
||||
|
||||
Hardware accelerated, Nintendo Switch inspired UI library for PC and Nintendo Switch. Powered by nanovg. Skeleton based on the [hybrid glfw app](https://github.com/fincs/hybrid_app) by fincs.
|
||||
|
||||
The library is still in early development and WILL lack features and contain bugs. Feel free to report them in the issues, or make a pull request if you happen to fix some.
|
||||
|
||||
You can see the planned features in the Projects tab.
|
||||
|
||||
Documentation is available [right here](https://github.com/natinusala/borealis/wiki). Warning: may not be up to date.
|
||||
|
||||
## Building the example for Switch
|
||||
|
||||
To build for Switch, a standard development environment must first be set up. In order to do so, [refer to the Getting Started guide](https://devkitpro.org/wiki/Getting_Started).
|
||||
|
||||
```bash
|
||||
(sudo) (dkp-)pacman -S switch-glfw switch-mesa switch-glm
|
||||
make -j
|
||||
nxlink -s borealis_example.nro
|
||||
```
|
||||
|
||||
## Building the example for PC
|
||||
|
||||
To build for PC, the following components are required:
|
||||
|
||||
- meson/ninja build system
|
||||
- A C++ compiler supporting the C++17 standard
|
||||
- GLFW version 3.3 or higher (as a static library)
|
||||
- GLM version 0.9.8 or higher
|
||||
|
||||
Please refer to the usual sources of information for your particular operating system. Usually the commands needed to build this project will look like this:
|
||||
|
||||
```bash
|
||||
meson build
|
||||
ninja -C build
|
||||
./build/borealis_example
|
||||
```
|
||||
|
||||
Also, please note that the `resources` folder must be available in the working directory, otherwise the program will fail to find the shaders.
|
||||
|
||||
### Building the example for Windows using msys2
|
||||
|
||||
msys2 provides all packages needed to build this project:
|
||||
|
||||
```bash
|
||||
pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-meson mingw-w64-x86_64-ninja mingw-w64-x86_64-pkg-config mingw-w64-x86_64-glfw mingw-w64-x86_64-glm
|
||||
meson build
|
||||
ninja -C build
|
||||
./build/borealis_example
|
||||
```
|
||||
|
||||
### Including in your project (TL;DR: see the example makefile in this repo)
|
||||
0. Your project must be built as C++17 (`-std=c++1z`). You also need to remove `-fno-rtti` and `-fno-exceptions` if you have them
|
||||
1. Use a submodule (or even better, a [subrepo](https://github.com/ingydotnet/git-subrepo)) to clone this repository in your project
|
||||
2. Copy the `resources` folder to the root of your project
|
||||
3. For PC (meson):
|
||||
1. take a standard meson file
|
||||
2. use `subdir` to import the library folder
|
||||
3. use the `borealis_files`, `borealis_dependencies` and `borealis_include` variables for respectively objects to build, dependencies (glfw...) and includes directory
|
||||
4. add a `BOREALIS_RESOURCES` define pointing to the resources folder at runtime (so `resources`)
|
||||
4. For Switch:
|
||||
1. take a standard homebrew makefile
|
||||
2. add a `BOREALIS_PATH` variable containing the subfolder you put the library in
|
||||
3. use `include` to load `borealis.mk` (after `LIBDIRS` and `BOREALIS_PATH`)
|
||||
4. set `ROMFS` to the resources folder
|
||||
5. add a `BOREALIS_RESOURCES` define pointing to the resources folder at runtime (so `romfs:/`)
|
||||
171
lib/borealis/example/main.cpp
Normal file
171
lib/borealis/example/main.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019-2020 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <borealis.hpp>
|
||||
#include <string>
|
||||
|
||||
#include "sample_installer_page.hpp"
|
||||
#include "sample_loading_page.hpp"
|
||||
|
||||
std::vector<std::string> NOTIFICATIONS = {
|
||||
"You have cool hair",
|
||||
"I like your shoes",
|
||||
"borealis is powered by nanovg",
|
||||
"The Triforce is an inside job",
|
||||
"Pozznx will trigger in one day and twelve hours",
|
||||
"Aurora Borealis? At this time of day, at this time of year, in this part of the gaming market, located entirely within your Switch?!",
|
||||
"May I see it?",
|
||||
"Hmm, Steamed Hams!"
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
// Init the app
|
||||
brls::Logger::setLogLevel(brls::LogLevel::DEBUG);
|
||||
|
||||
if (!brls::Application::init("Borealis example"))
|
||||
{
|
||||
brls::Logger::error("Unable to init Borealis application");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Create a sample view
|
||||
brls::TabFrame* rootFrame = new brls::TabFrame();
|
||||
rootFrame->setTitle("Borealis Example App");
|
||||
rootFrame->setIcon(BOREALIS_ASSET("icon/borealis.jpg"));
|
||||
|
||||
brls::List* testList = new brls::List();
|
||||
|
||||
brls::ListItem* dialogItem = new brls::ListItem("Open a dialog");
|
||||
dialogItem->getClickEvent()->subscribe([](brls::View* view) {
|
||||
brls::Dialog* dialog = new brls::Dialog("Warning: PozzNX will wipe all data on your Switch and render it inoperable, do you want to proceed?");
|
||||
|
||||
brls::GenericEvent::Callback closeCallback = [dialog](brls::View* view) {
|
||||
dialog->close();
|
||||
brls::Application::notify("Running PozzNX...");
|
||||
};
|
||||
|
||||
dialog->addButton("Continue", closeCallback);
|
||||
dialog->addButton("Continue", closeCallback);
|
||||
dialog->addButton("Continue", closeCallback);
|
||||
|
||||
dialog->setCancelable(false);
|
||||
|
||||
dialog->open();
|
||||
});
|
||||
|
||||
brls::ListItem* notificationItem = new brls::ListItem("Post a random notification");
|
||||
notificationItem->getClickEvent()->subscribe([](brls::View* view) {
|
||||
std::string notification = NOTIFICATIONS[std::rand() % NOTIFICATIONS.size()];
|
||||
brls::Application::notify(notification);
|
||||
});
|
||||
|
||||
brls::ListItem* themeItem = new brls::ListItem("TV Resolution");
|
||||
themeItem->setValue("Automatic");
|
||||
|
||||
brls::SelectListItem* jankItem = new brls::SelectListItem(
|
||||
"User Interface Jank",
|
||||
{ "Native", "Minimal", "Regular", "Maximum", "SX OS", "Windows Vista", "iOS 14" });
|
||||
|
||||
brls::ListItem* crashItem = new brls::ListItem("Divide by 0", "Can the Switch do it?");
|
||||
crashItem->getClickEvent()->subscribe([](brls::View* view) { brls::Application::crash("The software was closed because an error occured:\nSIGABRT (signal 6)"); });
|
||||
|
||||
brls::ListItem* popupItem = new brls::ListItem("Open popup");
|
||||
popupItem->getClickEvent()->subscribe([](brls::View* view) {
|
||||
brls::TabFrame* popupTabFrame = new brls::TabFrame();
|
||||
popupTabFrame->addTab("Red", new brls::Rectangle(nvgRGB(255, 0, 0)));
|
||||
popupTabFrame->addTab("Green", new brls::Rectangle(nvgRGB(0, 255, 0)));
|
||||
popupTabFrame->addTab("Blue", new brls::Rectangle(nvgRGB(0, 0, 255)));
|
||||
brls::PopupFrame::open("Popup title", BOREALIS_ASSET("icon/borealis.jpg"), popupTabFrame, "Subtitle left", "Subtitle right");
|
||||
});
|
||||
|
||||
brls::ListItem* installerItem = new brls::ListItem("Open example installer");
|
||||
installerItem->getClickEvent()->subscribe([](brls::View* view) {
|
||||
brls::StagedAppletFrame* stagedFrame = new brls::StagedAppletFrame();
|
||||
stagedFrame->setTitle("My great installer");
|
||||
|
||||
stagedFrame->addStage(new SampleInstallerPage(stagedFrame, "Go to step 2"));
|
||||
stagedFrame->addStage(new SampleLoadingPage(stagedFrame));
|
||||
stagedFrame->addStage(new SampleInstallerPage(stagedFrame, "Finish"));
|
||||
|
||||
brls::Application::pushView(stagedFrame);
|
||||
});
|
||||
|
||||
brls::SelectListItem* layerSelectItem = new brls::SelectListItem("Select Layer", { "Layer 1", "Layer 2" });
|
||||
|
||||
testList->addView(dialogItem);
|
||||
testList->addView(notificationItem);
|
||||
testList->addView(themeItem);
|
||||
testList->addView(jankItem);
|
||||
testList->addView(crashItem);
|
||||
testList->addView(installerItem);
|
||||
testList->addView(popupItem);
|
||||
|
||||
brls::Label* testLabel = new brls::Label(brls::LabelStyle::REGULAR, "For more information about how to use Nintendo Switch and its features, please refer to the Nintendo Support Website on your smart device or PC.", true);
|
||||
testList->addView(testLabel);
|
||||
|
||||
brls::ListItem* actionTestItem = new brls::ListItem("Custom Actions");
|
||||
actionTestItem->registerAction("Show notification", brls::Key::L, [] {
|
||||
brls::Application::notify("Custom Action triggered");
|
||||
return true;
|
||||
});
|
||||
testList->addView(actionTestItem);
|
||||
|
||||
brls::LayerView* testLayers = new brls::LayerView();
|
||||
brls::List* layerList1 = new brls::List();
|
||||
brls::List* layerList2 = new brls::List();
|
||||
|
||||
layerList1->addView(new brls::Header("Layer 1", false));
|
||||
layerList1->addView(new brls::ListItem("Item 1"));
|
||||
layerList1->addView(new brls::ListItem("Item 2"));
|
||||
layerList1->addView(new brls::ListItem("Item 3"));
|
||||
|
||||
layerList2->addView(new brls::Header("Layer 2", false));
|
||||
layerList2->addView(new brls::ListItem("Item 1"));
|
||||
layerList2->addView(new brls::ListItem("Item 2"));
|
||||
layerList2->addView(new brls::ListItem("Item 3"));
|
||||
|
||||
testLayers->addLayer(layerList1);
|
||||
testLayers->addLayer(layerList2);
|
||||
|
||||
layerSelectItem->getValueSelectedEvent()->subscribe([=](size_t selection) {
|
||||
testLayers->changeLayer(selection);
|
||||
});
|
||||
|
||||
testList->addView(layerSelectItem);
|
||||
|
||||
rootFrame->addTab("First tab", testList);
|
||||
rootFrame->addTab("Second tab", testLayers);
|
||||
rootFrame->addSeparator();
|
||||
rootFrame->addTab("Third tab", new brls::Rectangle(nvgRGB(255, 0, 0)));
|
||||
rootFrame->addTab("Fourth tab", new brls::Rectangle(nvgRGB(0, 255, 0)));
|
||||
|
||||
// Add the root view to the stack
|
||||
brls::Application::pushView(rootFrame);
|
||||
|
||||
// Run the app
|
||||
while (brls::Application::mainLoop())
|
||||
;
|
||||
|
||||
// Exit
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
75
lib/borealis/example/sample_installer_page.cpp
Normal file
75
lib/borealis/example/sample_installer_page.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 Billy Laws
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "sample_installer_page.hpp"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
SampleInstallerPage::SampleInstallerPage(brls::StagedAppletFrame* frame, std::string label)
|
||||
{
|
||||
// Label
|
||||
this->button = (new brls::Button(brls::ButtonStyle::BORDERLESS))->setLabel(label)->setImage(BOREALIS_ASSET("icon/borealis.jpg"));
|
||||
this->button->setParent(this);
|
||||
this->button->getClickEvent()->subscribe([frame](View* view) {
|
||||
if (frame->isLastStage())
|
||||
brls::Application::popView();
|
||||
else
|
||||
frame->nextStage();
|
||||
});
|
||||
this->label = new brls::Label(brls::LabelStyle::DIALOG, "Here, you would normally do useful things", true);
|
||||
this->label->setHorizontalAlign(NVG_ALIGN_CENTER);
|
||||
this->label->setParent(this);
|
||||
}
|
||||
|
||||
void SampleInstallerPage::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx)
|
||||
{
|
||||
this->label->frame(ctx);
|
||||
this->button->frame(ctx);
|
||||
}
|
||||
|
||||
brls::View* SampleInstallerPage::getDefaultFocus()
|
||||
{
|
||||
return this->button;
|
||||
}
|
||||
|
||||
void SampleInstallerPage::layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash)
|
||||
{
|
||||
this->label->setWidth(roundf((float)this->width * style->CrashFrame.labelWidth));
|
||||
this->label->invalidate(true);
|
||||
|
||||
this->label->setBoundaries(
|
||||
this->x + this->width / 2 - this->label->getWidth() / 2,
|
||||
this->y + (this->height - style->AppletFrame.footerHeight) / 2,
|
||||
this->label->getWidth(),
|
||||
this->label->getHeight());
|
||||
|
||||
this->button->setBoundaries(
|
||||
this->x + this->width / 2 - style->CrashFrame.buttonWidth / 2,
|
||||
this->y + this->height / 2 + style->CrashFrame.buttonHeight,
|
||||
style->CrashFrame.buttonWidth,
|
||||
style->CrashFrame.buttonHeight);
|
||||
this->button->invalidate();
|
||||
}
|
||||
|
||||
SampleInstallerPage::~SampleInstallerPage()
|
||||
{
|
||||
delete this->label;
|
||||
delete this->button;
|
||||
}
|
||||
38
lib/borealis/example/sample_installer_page.hpp
Normal file
38
lib/borealis/example/sample_installer_page.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 Billy Laws
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis.hpp>
|
||||
|
||||
class SampleInstallerPage : public brls::View
|
||||
{
|
||||
private:
|
||||
brls::Button* button;
|
||||
brls::Label* label;
|
||||
|
||||
public:
|
||||
SampleInstallerPage(brls::StagedAppletFrame* frame, std::string label);
|
||||
~SampleInstallerPage();
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx) override;
|
||||
void layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash) override;
|
||||
brls::View* getDefaultFocus() override;
|
||||
};
|
||||
80
lib/borealis/example/sample_loading_page.cpp
Normal file
80
lib/borealis/example/sample_loading_page.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 Billy Laws
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "sample_loading_page.hpp"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
SampleLoadingPage::SampleLoadingPage(brls::StagedAppletFrame* frame)
|
||||
: frame(frame)
|
||||
{
|
||||
// Label
|
||||
this->progressDisp = new brls::ProgressDisplay();
|
||||
this->progressDisp->setProgress(this->progressValue, 1000);
|
||||
this->progressDisp->setParent(this);
|
||||
this->label = new brls::Label(brls::LabelStyle::DIALOG, "Example loading display", true);
|
||||
this->label->setHorizontalAlign(NVG_ALIGN_CENTER);
|
||||
this->label->setParent(this);
|
||||
}
|
||||
|
||||
void SampleLoadingPage::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx)
|
||||
{
|
||||
if (progressValue == 500)
|
||||
this->frame->nextStage();
|
||||
|
||||
this->progressValue++;
|
||||
this->progressDisp->setProgress(this->progressValue, 500);
|
||||
this->progressDisp->frame(ctx);
|
||||
this->label->frame(ctx);
|
||||
}
|
||||
|
||||
void SampleLoadingPage::layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash)
|
||||
{
|
||||
this->label->setWidth(roundf((float)this->width * style->CrashFrame.labelWidth));
|
||||
this->label->invalidate(true);
|
||||
|
||||
this->label->setBoundaries(
|
||||
this->x + this->width / 2 - this->label->getWidth() / 2,
|
||||
this->y + (this->height - style->AppletFrame.footerHeight) / 2,
|
||||
this->label->getWidth(),
|
||||
this->label->getHeight());
|
||||
|
||||
this->progressDisp->setBoundaries(
|
||||
this->x + this->width / 2 - style->CrashFrame.buttonWidth,
|
||||
this->y + this->height / 2,
|
||||
style->CrashFrame.buttonWidth * 2,
|
||||
style->CrashFrame.buttonHeight);
|
||||
}
|
||||
|
||||
void SampleLoadingPage::willAppear(bool resetState)
|
||||
{
|
||||
this->progressDisp->willAppear(resetState);
|
||||
}
|
||||
|
||||
void SampleLoadingPage::willDisappear(bool resetState)
|
||||
{
|
||||
this->progressDisp->willDisappear(resetState);
|
||||
}
|
||||
|
||||
SampleLoadingPage::~SampleLoadingPage()
|
||||
{
|
||||
delete this->progressDisp;
|
||||
delete this->label;
|
||||
}
|
||||
42
lib/borealis/example/sample_loading_page.hpp
Normal file
42
lib/borealis/example/sample_loading_page.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 Billy Laws
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis.hpp>
|
||||
|
||||
class SampleLoadingPage : public brls::View
|
||||
{
|
||||
private:
|
||||
brls::StagedAppletFrame* frame;
|
||||
brls::ProgressDisplay* progressDisp;
|
||||
brls::Label* label;
|
||||
int progressValue = 0;
|
||||
|
||||
public:
|
||||
SampleLoadingPage(brls::StagedAppletFrame* frame);
|
||||
~SampleLoadingPage();
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx) override;
|
||||
void layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash) override;
|
||||
|
||||
void willAppear(bool resetState = false) override;
|
||||
void willDisappear(bool resetState = false) override;
|
||||
};
|
||||
18
lib/borealis/library/borealis.mk
Normal file
18
lib/borealis/library/borealis.mk
Normal file
@@ -0,0 +1,18 @@
|
||||
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
current_dir := $(BOREALIS_PATH)/$(notdir $(patsubst %/,%,$(dir $(mkfile_path))))
|
||||
|
||||
LIBS := -lglfw3 -lEGL -lglapi -ldrm_nouveau -lm $(LIBS)
|
||||
|
||||
SOURCES := $(SOURCES) \
|
||||
$(current_dir)/lib \
|
||||
$(current_dir)/lib/extern/glad \
|
||||
$(current_dir)/lib/extern/nanovg \
|
||||
$(current_dir)/lib/extern/libretro-common/compat \
|
||||
$(current_dir)/lib/extern/libretro-common/encodings \
|
||||
$(current_dir)/lib/extern/libretro-common/features
|
||||
|
||||
INCLUDES := $(INCLUDES) \
|
||||
$(current_dir)/include \
|
||||
$(current_dir)/include/borealis/extern/glad \
|
||||
$(current_dir)/include/borealis/extern/nanovg \
|
||||
$(current_dir)/include/borealis/extern/libretro-common
|
||||
56
lib/borealis/library/include/borealis.hpp
Normal file
56
lib/borealis/library/include/borealis.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef BOREALIS_RESOURCES
|
||||
#error BOREALIS_RESOURCES define missing
|
||||
#endif
|
||||
#define BOREALIS_ASSET(_str) BOREALIS_RESOURCES _str
|
||||
|
||||
// Library
|
||||
#include <borealis/applet_frame.hpp>
|
||||
#include <borealis/application.hpp>
|
||||
#include <borealis/box_layout.hpp>
|
||||
#include <borealis/button.hpp>
|
||||
#include <borealis/crash_frame.hpp>
|
||||
#include <borealis/dialog.hpp>
|
||||
#include <borealis/dropdown.hpp>
|
||||
#include <borealis/event.hpp>
|
||||
#include <borealis/header.hpp>
|
||||
#include <borealis/image.hpp>
|
||||
#include <borealis/label.hpp>
|
||||
#include <borealis/layer_view.hpp>
|
||||
#include <borealis/list.hpp>
|
||||
#include <borealis/logger.hpp>
|
||||
#include <borealis/material_icon.hpp>
|
||||
#include <borealis/notification_manager.hpp>
|
||||
#include <borealis/popup_frame.hpp>
|
||||
#include <borealis/progress_display.hpp>
|
||||
#include <borealis/progress_spinner.hpp>
|
||||
#include <borealis/rectangle.hpp>
|
||||
#include <borealis/repeating_task.hpp>
|
||||
#include <borealis/sidebar.hpp>
|
||||
#include <borealis/staged_applet_frame.hpp>
|
||||
#include <borealis/style.hpp>
|
||||
#include <borealis/tab_frame.hpp>
|
||||
#include <borealis/table.hpp>
|
||||
#include <borealis/theme.hpp>
|
||||
#include <borealis/thumbnail_frame.hpp>
|
||||
#include <borealis/view.hpp>
|
||||
68
lib/borealis/library/include/borealis/actions.hpp
Normal file
68
lib/borealis/library/include/borealis/actions.hpp
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2020 WerWolv
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#define GLFW_INCLUDE_NONE
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
class View;
|
||||
|
||||
typedef std::function<bool(void)> ActionListener;
|
||||
|
||||
// ZL and ZR do not exist here because GLFW doesn't know them
|
||||
enum class Key
|
||||
{
|
||||
A = GLFW_GAMEPAD_BUTTON_A,
|
||||
B = GLFW_GAMEPAD_BUTTON_B,
|
||||
X = GLFW_GAMEPAD_BUTTON_X,
|
||||
Y = GLFW_GAMEPAD_BUTTON_Y,
|
||||
LSTICK = GLFW_GAMEPAD_BUTTON_LEFT_THUMB,
|
||||
RSTICK = GLFW_GAMEPAD_BUTTON_RIGHT_THUMB,
|
||||
L = GLFW_GAMEPAD_BUTTON_LEFT_BUMPER,
|
||||
R = GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER,
|
||||
PLUS = GLFW_GAMEPAD_BUTTON_START,
|
||||
MINUS = GLFW_GAMEPAD_BUTTON_BACK,
|
||||
DLEFT = GLFW_GAMEPAD_BUTTON_DPAD_LEFT,
|
||||
DUP = GLFW_GAMEPAD_BUTTON_DPAD_UP,
|
||||
DRIGHT = GLFW_GAMEPAD_BUTTON_DPAD_RIGHT,
|
||||
DDOWN = GLFW_GAMEPAD_BUTTON_DPAD_DOWN,
|
||||
};
|
||||
|
||||
struct Action
|
||||
{
|
||||
Key key;
|
||||
|
||||
std::string hintText;
|
||||
bool available;
|
||||
bool hidden;
|
||||
ActionListener actionListener;
|
||||
|
||||
bool operator==(const Key other)
|
||||
{
|
||||
return this->key == other;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
178
lib/borealis/library/include/borealis/animations.hpp
Normal file
178
lib/borealis/library/include/borealis/animations.hpp
Normal file
@@ -0,0 +1,178 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Borealis, a Nintendo Switch UI Library
|
||||
* Copyright (C) 2014-2017 - Jean-André Santoni
|
||||
* Copyright (C) 2011-2017 - Daniel De Matteis
|
||||
* Copyright (C) 2019 - natinusala
|
||||
Copyright (C) 2019 - p-sam
|
||||
*
|
||||
* RetroArch 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 Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch 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 RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
typedef float (*easing_cb)(float, float, float, float);
|
||||
typedef std::function<void(void*)> tween_cb;
|
||||
|
||||
enum menu_animation_ctl_state
|
||||
{
|
||||
MENU_ANIMATION_CTL_NONE = 0,
|
||||
MENU_ANIMATION_CTL_DEINIT,
|
||||
MENU_ANIMATION_CTL_CLEAR_ACTIVE,
|
||||
MENU_ANIMATION_CTL_SET_ACTIVE
|
||||
};
|
||||
|
||||
enum menu_animation_easing_type
|
||||
{
|
||||
/* Linear */
|
||||
EASING_LINEAR = 0,
|
||||
/* Quad */
|
||||
EASING_IN_QUAD,
|
||||
EASING_OUT_QUAD,
|
||||
EASING_IN_OUT_QUAD,
|
||||
EASING_OUT_IN_QUAD,
|
||||
/* Cubic */
|
||||
EASING_IN_CUBIC,
|
||||
EASING_OUT_CUBIC,
|
||||
EASING_IN_OUT_CUBIC,
|
||||
EASING_OUT_IN_CUBIC,
|
||||
/* Quart */
|
||||
EASING_IN_QUART,
|
||||
EASING_OUT_QUART,
|
||||
EASING_IN_OUT_QUART,
|
||||
EASING_OUT_IN_QUART,
|
||||
/* Quint */
|
||||
EASING_IN_QUINT,
|
||||
EASING_OUT_QUINT,
|
||||
EASING_IN_OUT_QUINT,
|
||||
EASING_OUT_IN_QUINT,
|
||||
/* Sine */
|
||||
EASING_IN_SINE,
|
||||
EASING_OUT_SINE,
|
||||
EASING_IN_OUT_SINE,
|
||||
EASING_OUT_IN_SINE,
|
||||
/* Expo */
|
||||
EASING_IN_EXPO,
|
||||
EASING_OUT_EXPO,
|
||||
EASING_IN_OUT_EXPO,
|
||||
EASING_OUT_IN_EXPO,
|
||||
/* Circ */
|
||||
EASING_IN_CIRC,
|
||||
EASING_OUT_CIRC,
|
||||
EASING_IN_OUT_CIRC,
|
||||
EASING_OUT_IN_CIRC,
|
||||
/* Bounce */
|
||||
EASING_IN_BOUNCE,
|
||||
EASING_OUT_BOUNCE,
|
||||
EASING_IN_OUT_BOUNCE,
|
||||
EASING_OUT_IN_BOUNCE,
|
||||
|
||||
EASING_LAST
|
||||
};
|
||||
|
||||
/* TODO:
|
||||
* Add a reverse loop ticker for languages
|
||||
* that read right to left */
|
||||
enum menu_animation_ticker_type
|
||||
{
|
||||
TICKER_TYPE_BOUNCE = 0,
|
||||
TICKER_TYPE_LOOP,
|
||||
TICKER_TYPE_LAST
|
||||
};
|
||||
|
||||
typedef uintptr_t menu_animation_ctx_tag;
|
||||
|
||||
typedef struct menu_animation_ctx_subject
|
||||
{
|
||||
size_t count;
|
||||
const void* data;
|
||||
} menu_animation_ctx_subject_t;
|
||||
|
||||
typedef struct menu_animation_ctx_entry
|
||||
{
|
||||
enum menu_animation_easing_type easing_enum;
|
||||
uintptr_t tag;
|
||||
float duration;
|
||||
float target_value;
|
||||
float* subject;
|
||||
tween_cb cb;
|
||||
tween_cb tick;
|
||||
void* userdata;
|
||||
} menu_animation_ctx_entry_t;
|
||||
|
||||
typedef struct menu_animation_ctx_ticker
|
||||
{
|
||||
bool selected;
|
||||
size_t len;
|
||||
uint64_t idx;
|
||||
enum menu_animation_ticker_type type_enum;
|
||||
char* s;
|
||||
const char* str;
|
||||
const char* spacer;
|
||||
} menu_animation_ctx_ticker_t;
|
||||
|
||||
typedef float menu_timer_t;
|
||||
|
||||
typedef struct menu_timer_ctx_entry
|
||||
{
|
||||
float duration;
|
||||
tween_cb cb;
|
||||
tween_cb tick;
|
||||
void* userdata;
|
||||
} menu_timer_ctx_entry_t;
|
||||
|
||||
typedef struct menu_delayed_animation
|
||||
{
|
||||
menu_timer_t timer;
|
||||
menu_animation_ctx_entry_t entry;
|
||||
} menu_delayed_animation_t;
|
||||
|
||||
void menu_timer_start(menu_timer_t* timer, menu_timer_ctx_entry_t* timer_entry);
|
||||
|
||||
void menu_timer_kill(menu_timer_t* timer);
|
||||
|
||||
void menu_animation_init(void);
|
||||
|
||||
void menu_animation_free(void);
|
||||
|
||||
bool menu_animation_update(void);
|
||||
|
||||
bool menu_animation_ticker(menu_animation_ctx_ticker_t* ticker);
|
||||
|
||||
float menu_animation_get_delta_time(void);
|
||||
|
||||
bool menu_animation_is_active(void);
|
||||
|
||||
bool menu_animation_kill_by_tag(menu_animation_ctx_tag* tag);
|
||||
|
||||
void menu_animation_kill_by_subject(menu_animation_ctx_subject_t* subject);
|
||||
|
||||
bool menu_animation_push(menu_animation_ctx_entry_t* entry);
|
||||
|
||||
void menu_animation_push_delayed(unsigned delay, menu_animation_ctx_entry_t* entry);
|
||||
|
||||
bool menu_animation_ctl(enum menu_animation_ctl_state state, void* data);
|
||||
|
||||
uint64_t menu_animation_get_ticker_idx(void);
|
||||
|
||||
uint64_t menu_animation_get_ticker_slow_idx(void);
|
||||
|
||||
void menu_animation_get_highlight(float* gradient_x, float* gradient_y, float* color);
|
||||
|
||||
} // namespace brls
|
||||
94
lib/borealis/library/include/borealis/applet_frame.hpp
Normal file
94
lib/borealis/library/include/borealis/applet_frame.hpp
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/frame_context.hpp>
|
||||
#include <borealis/hint.hpp>
|
||||
#include <borealis/image.hpp>
|
||||
#include <borealis/view.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
enum class HeaderStyle
|
||||
{
|
||||
REGULAR,
|
||||
POPUP // Only meant for PopupFrames. Using it in other contexts might cause weird behaviour
|
||||
};
|
||||
|
||||
// A Horizon settings-like frame, with header and footer (no sidebar)
|
||||
class AppletFrame : public View
|
||||
{
|
||||
private:
|
||||
std::string title = "";
|
||||
std::string footerText = "";
|
||||
|
||||
std::string subTitleLeft = "", subTitleRight = "";
|
||||
|
||||
View* icon = nullptr;
|
||||
Hint* hint = nullptr;
|
||||
|
||||
View* contentView = nullptr;
|
||||
|
||||
bool slideOut = false;
|
||||
bool slideIn = false;
|
||||
|
||||
ViewAnimation animation;
|
||||
|
||||
protected:
|
||||
HeaderStyle headerStyle = HeaderStyle::REGULAR;
|
||||
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
|
||||
|
||||
unsigned leftPadding = 0;
|
||||
unsigned rightPadding = 0;
|
||||
|
||||
public:
|
||||
AppletFrame(bool padLeft, bool padRight);
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
View* getDefaultFocus() override;
|
||||
virtual bool onCancel();
|
||||
void willAppear(bool resetState = false) override;
|
||||
void willDisappear(bool resetState = false) override;
|
||||
void show(std::function<void(void)> cb, bool animate = true, ViewAnimation animation = ViewAnimation::FADE) override;
|
||||
void hide(std::function<void(void)> cb, bool animated = true, ViewAnimation animation = ViewAnimation::FADE) override;
|
||||
void onWindowSizeChanged() override;
|
||||
|
||||
void setTitle(std::string title);
|
||||
void setFooterText(std::string footerText);
|
||||
void setSubtitle(std::string left, std::string right);
|
||||
void setIcon(unsigned char* buffer, size_t bufferSize);
|
||||
void setIcon(std::string imagePath);
|
||||
void setIcon(View* view);
|
||||
virtual void setContentView(View* view);
|
||||
bool hasContentView();
|
||||
void setHeaderStyle(HeaderStyle headerStyle);
|
||||
|
||||
void setAnimateHint(bool animate)
|
||||
{
|
||||
this->hint->setAnimate(animate);
|
||||
}
|
||||
|
||||
~AppletFrame();
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
204
lib/borealis/library/include/borealis/application.hpp
Normal file
204
lib/borealis/library/include/borealis/application.hpp
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019-2020 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define GLFW_INCLUDE_NONE
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <nanovg.h>
|
||||
|
||||
#include <borealis/animations.hpp>
|
||||
#include <borealis/frame_context.hpp>
|
||||
#include <borealis/hint.hpp>
|
||||
#include <borealis/label.hpp>
|
||||
#include <borealis/logger.hpp>
|
||||
#include <borealis/notification_manager.hpp>
|
||||
#include <borealis/style.hpp>
|
||||
#include <borealis/task_manager.hpp>
|
||||
#include <borealis/theme.hpp>
|
||||
#include <borealis/view.hpp>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// The top-right framerate counter
|
||||
class FramerateCounter : public Label
|
||||
{
|
||||
private:
|
||||
retro_time_t lastSecond = 0;
|
||||
unsigned frames = 0;
|
||||
|
||||
public:
|
||||
FramerateCounter();
|
||||
|
||||
void frame(FrameContext* ctx) override;
|
||||
};
|
||||
|
||||
class Application
|
||||
{
|
||||
public:
|
||||
//Init with default style and theme (as close to HOS as possible)
|
||||
static bool init(std::string title);
|
||||
|
||||
// Init with given style and theme
|
||||
static bool init(std::string title, Style style, Theme theme);
|
||||
|
||||
static bool mainLoop();
|
||||
|
||||
/**
|
||||
* Pushes a view on this applications's view stack
|
||||
*
|
||||
* The view will automatically be resized to take
|
||||
* the whole screen and layout() will be called
|
||||
*
|
||||
* The view will gain focus if applicable
|
||||
*/
|
||||
static void pushView(View* view, ViewAnimation animation = ViewAnimation::FADE);
|
||||
|
||||
/**
|
||||
* Pops the last pushed view from the stack
|
||||
* and gives focus back where it was before
|
||||
*/
|
||||
static void popView(
|
||||
ViewAnimation animation = ViewAnimation::FADE, std::function<void(void)> cb = []() {});
|
||||
|
||||
/**
|
||||
* Gives the focus to the given view
|
||||
* or clears the focus if given nullptr
|
||||
*/
|
||||
static void giveFocus(View* view);
|
||||
|
||||
static Style* getStyle();
|
||||
static void setTheme(Theme theme);
|
||||
static ThemeValues* getThemeValues();
|
||||
static ThemeValues* getThemeValuesForVariant(ThemeVariant variant);
|
||||
static ThemeVariant getThemeVariant();
|
||||
|
||||
static int loadFont(const char* fontName, const char* filePath);
|
||||
static int loadFontFromMemory(const char* fontName, void* data, size_t size, bool freeData);
|
||||
static int findFont(const char* fontName);
|
||||
|
||||
static FontStash* getFontStash();
|
||||
|
||||
static void notify(std::string text);
|
||||
|
||||
static void onGamepadButtonPressed(char button, bool repeating);
|
||||
|
||||
/**
|
||||
* "Crashes" the app (displays a fullscreen CrashFrame)
|
||||
*/
|
||||
static void crash(std::string text);
|
||||
|
||||
static void quit();
|
||||
|
||||
/**
|
||||
* Blocks any and all user inputs
|
||||
*/
|
||||
static void blockInputs();
|
||||
|
||||
/**
|
||||
* Unblocks inputs after a call to
|
||||
* blockInputs()
|
||||
*/
|
||||
static void unblockInputs();
|
||||
|
||||
static NVGcontext* getNVGContext();
|
||||
static TaskManager* getTaskManager();
|
||||
static NotificationManager* getNotificationManager();
|
||||
|
||||
static void setCommonFooter(std::string footer);
|
||||
static std::string* getCommonFooter();
|
||||
|
||||
static void setDisplayFramerate(bool enabled);
|
||||
static void toggleFramerateDisplay();
|
||||
|
||||
static void setMaximumFPS(unsigned fps);
|
||||
|
||||
// public so that the glfw callback can access it
|
||||
inline static unsigned contentWidth, contentHeight;
|
||||
inline static float windowScale;
|
||||
|
||||
static void resizeFramerateCounter();
|
||||
static void resizeNotificationManager();
|
||||
|
||||
static GenericEvent* getGlobalFocusChangeEvent();
|
||||
static VoidEvent* getGlobalHintsUpdateEvent();
|
||||
|
||||
static View* getCurrentFocus();
|
||||
|
||||
static std::string getTitle();
|
||||
|
||||
private:
|
||||
inline static GLFWwindow* window;
|
||||
inline static NVGcontext* vg;
|
||||
|
||||
inline static std::string title;
|
||||
|
||||
inline static TaskManager* taskManager;
|
||||
inline static NotificationManager* notificationManager;
|
||||
|
||||
inline static FontStash fontStash;
|
||||
|
||||
inline static std::vector<View*> viewStack;
|
||||
inline static std::vector<View*> focusStack;
|
||||
|
||||
inline static unsigned windowWidth, windowHeight;
|
||||
|
||||
inline static View* currentFocus;
|
||||
|
||||
inline static Theme currentTheme;
|
||||
inline static ThemeVariant currentThemeVariant;
|
||||
|
||||
inline static GLFWgamepadstate oldGamepad;
|
||||
inline static GLFWgamepadstate gamepad;
|
||||
|
||||
inline static Style currentStyle;
|
||||
|
||||
inline static unsigned blockInputsTokens = 0; // any value > 0 means inputs are blocked
|
||||
|
||||
inline static std::string commonFooter = "";
|
||||
|
||||
inline static FramerateCounter* framerateCounter = nullptr;
|
||||
|
||||
inline static float frameTime = 0.0f;
|
||||
|
||||
inline static View* repetitionOldFocus = nullptr;
|
||||
|
||||
inline static GenericEvent globalFocusChangeEvent;
|
||||
inline static VoidEvent globalHintsUpdateEvent;
|
||||
|
||||
static void navigate(FocusDirection direction);
|
||||
|
||||
static void onWindowSizeChanged();
|
||||
|
||||
static void frame();
|
||||
static void clear();
|
||||
static void exit();
|
||||
|
||||
/**
|
||||
* Handles actions for the currently focused view and
|
||||
* the given button
|
||||
* Returns true if at least one action has been fired
|
||||
*/
|
||||
static bool handleAction(char button);
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
173
lib/borealis/library/include/borealis/box_layout.hpp
Normal file
173
lib/borealis/library/include/borealis/box_layout.hpp
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 WerWolv
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/view.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
enum class BoxLayoutOrientation
|
||||
{
|
||||
VERTICAL,
|
||||
HORIZONTAL
|
||||
};
|
||||
|
||||
// TODO: Implement all gravity options for both orientations
|
||||
enum class BoxLayoutGravity
|
||||
{
|
||||
DEFAULT, // left for horizontal, top for vertical
|
||||
LEFT,
|
||||
RIGHT,
|
||||
TOP,
|
||||
BOTTOM,
|
||||
CENTER
|
||||
};
|
||||
|
||||
class BoxLayoutChild
|
||||
{
|
||||
public:
|
||||
View* view;
|
||||
bool fill; // should the child fill the remaining space?
|
||||
};
|
||||
|
||||
// A basic horizontal or vertical box layout :
|
||||
// - Children can currently only be stretched to full width (vertical) or height (horizontal)
|
||||
// - Only works with children with fixed width (horizontal) or height (vertical)
|
||||
|
||||
// TODO: More complex alignment and/or stretching parameters to children
|
||||
class BoxLayout : public View
|
||||
{
|
||||
private:
|
||||
BoxLayoutOrientation orientation;
|
||||
|
||||
unsigned spacing = 0;
|
||||
|
||||
bool resize = false; // should the view be resized according to children size after a layout?
|
||||
|
||||
BoxLayoutGravity gravity = BoxLayoutGravity::DEFAULT;
|
||||
|
||||
protected:
|
||||
std::vector<BoxLayoutChild*> children;
|
||||
|
||||
size_t originalDefaultFocus = 0;
|
||||
size_t defaultFocusedIndex = 0;
|
||||
bool childFocused = false;
|
||||
|
||||
bool rememberFocus = false;
|
||||
|
||||
unsigned marginTop = 0;
|
||||
unsigned marginRight = 0;
|
||||
unsigned marginBottom = 0;
|
||||
unsigned marginLeft = 0;
|
||||
|
||||
/**
|
||||
* Should the BoxLayout apply spacing after
|
||||
* this view?
|
||||
*/
|
||||
virtual void customSpacing(View* current, View* next, int* spacing) {}
|
||||
|
||||
public:
|
||||
BoxLayout(BoxLayoutOrientation orientation, size_t defaultFocus = 0);
|
||||
~BoxLayout();
|
||||
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
View* getNextFocus(FocusDirection direction, void* parentUserdata) override;
|
||||
View* getDefaultFocus() override;
|
||||
void onChildFocusGained(View* child) override;
|
||||
void onChildFocusLost(View* child) override;
|
||||
void willAppear(bool resetState = false) override;
|
||||
void willDisappear(bool resetState = false) override;
|
||||
void onWindowSizeChanged() override;
|
||||
|
||||
/**
|
||||
* Sets gravity
|
||||
*/
|
||||
void setGravity(BoxLayoutGravity gravity);
|
||||
|
||||
/**
|
||||
* Sets spacing between views
|
||||
*/
|
||||
void setSpacing(unsigned spacing);
|
||||
unsigned getSpacing();
|
||||
|
||||
/**
|
||||
* Sets margins around views
|
||||
* Bottom (vertical) or right (horizontal) are
|
||||
* only effective if the last child is set to fill
|
||||
*/
|
||||
void setMargins(unsigned top, unsigned right, unsigned bottom, unsigned left);
|
||||
void setMarginBottom(unsigned bottom);
|
||||
|
||||
/**
|
||||
* Adds a view to this box layout
|
||||
* If fill is set to true, the child will
|
||||
* fill the remaining space
|
||||
*/
|
||||
void addView(View* view, bool fill = false, bool resetState = false);
|
||||
|
||||
/**
|
||||
* Removes the view at specified
|
||||
* The view will be freed if free
|
||||
* is set to true (defaults to true)
|
||||
*
|
||||
* Warning: this method isn't correctly
|
||||
* implemented - currently removing a view will
|
||||
* most likely result in memory corruption
|
||||
*/
|
||||
void removeView(int index, bool free = true);
|
||||
|
||||
/**
|
||||
* Removes all views
|
||||
* from this layout
|
||||
*/
|
||||
void clear(bool free = true);
|
||||
|
||||
/**
|
||||
* Returns true if this layout
|
||||
* doesn't contain any views
|
||||
*/
|
||||
bool isEmpty();
|
||||
|
||||
bool isChildFocused();
|
||||
|
||||
void setFocusedIndex(unsigned index);
|
||||
size_t getViewsCount();
|
||||
|
||||
View* getChild(size_t i);
|
||||
|
||||
/**
|
||||
* If enabled, will force the layout to resize itself
|
||||
* to match the children size
|
||||
* Mandatory for using in a ScrollView
|
||||
*/
|
||||
void setResize(bool resize);
|
||||
|
||||
/**
|
||||
* Should the default focus be set to the originally focused
|
||||
* view (until the layout disappears)?
|
||||
*/
|
||||
void setRememberFocus(bool rememberFocus);
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
99
lib/borealis/library/include/borealis/button.hpp
Normal file
99
lib/borealis/library/include/borealis/button.hpp
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019-2020 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/image.hpp>
|
||||
#include <borealis/label.hpp>
|
||||
#include <borealis/view.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
enum class ButtonStyle
|
||||
{
|
||||
PLAIN = 0, // regular, plain button
|
||||
BORDERED, // text and a border
|
||||
BORDERLESS, // only text
|
||||
CRASH, // same as borderless but with a different text color
|
||||
DIALOG // same as borderless but with a different text color
|
||||
};
|
||||
|
||||
enum class ButtonState
|
||||
{
|
||||
ENABLED = 0,
|
||||
DISABLED
|
||||
};
|
||||
|
||||
// A button
|
||||
class Button : public View
|
||||
{
|
||||
private:
|
||||
ButtonStyle style;
|
||||
Label* label = nullptr;
|
||||
Image* image = nullptr;
|
||||
|
||||
GenericEvent clickEvent;
|
||||
|
||||
LabelStyle getLabelStyle();
|
||||
|
||||
ButtonState state = ButtonState::ENABLED;
|
||||
|
||||
float cornerRadiusOverride = 0;
|
||||
|
||||
public:
|
||||
Button(ButtonStyle style);
|
||||
~Button();
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
virtual bool onClick();
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash);
|
||||
void getHighlightInsets(unsigned* top, unsigned* right, unsigned* bottom, unsigned* left) override;
|
||||
|
||||
ButtonState getState();
|
||||
void setState(ButtonState state);
|
||||
|
||||
Button* setLabel(std::string label);
|
||||
Button* setImage(std::string path);
|
||||
Button* setImage(unsigned char* buffer, size_t bufferSize);
|
||||
|
||||
GenericEvent* getClickEvent();
|
||||
|
||||
View* getDefaultFocus() override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void setCornerRadius(float cornerRadius);
|
||||
|
||||
void getHighlightMetrics(Style* style, float* cornerRadius) override
|
||||
{
|
||||
if (cornerRadiusOverride)
|
||||
*cornerRadius = cornerRadiusOverride;
|
||||
else
|
||||
*cornerRadius = style->Button.cornerRadius;
|
||||
}
|
||||
|
||||
bool isHighlightBackgroundEnabled() override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
55
lib/borealis/library/include/borealis/crash_frame.hpp
Normal file
55
lib/borealis/library/include/borealis/crash_frame.hpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019-2020 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/button.hpp>
|
||||
#include <borealis/hint.hpp>
|
||||
#include <borealis/label.hpp>
|
||||
#include <borealis/view.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// A screen similar to the "The software has closed" dialog
|
||||
// pressing OK will exit the app
|
||||
class CrashFrame : public View
|
||||
{
|
||||
private:
|
||||
Label* label;
|
||||
Button* button;
|
||||
Hint* hint;
|
||||
|
||||
public:
|
||||
CrashFrame(std::string text);
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
|
||||
void onShowAnimationEnd() override;
|
||||
View* getDefaultFocus() override;
|
||||
|
||||
bool isTranslucent() override
|
||||
{
|
||||
return true; // have it always translucent to disable fade out animation
|
||||
}
|
||||
|
||||
~CrashFrame();
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
95
lib/borealis/library/include/borealis/dialog.hpp
Normal file
95
lib/borealis/library/include/borealis/dialog.hpp
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019-2020 natinusala
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/box_layout.hpp>
|
||||
#include <borealis/view.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// TODO: Add a "can be cancelled with B" flag
|
||||
// TODO: Add buttons at creation time
|
||||
// TODO: Add the blurred dialog type once the blur is finished
|
||||
|
||||
class DialogButton
|
||||
{
|
||||
public:
|
||||
std::string label;
|
||||
GenericEvent::Callback cb;
|
||||
};
|
||||
|
||||
// A modal dialog with zero to three buttons
|
||||
// and anything as content
|
||||
// Create the dialog then use open() and close()
|
||||
class Dialog : public View
|
||||
{
|
||||
private:
|
||||
View* contentView = nullptr;
|
||||
|
||||
unsigned frameX, frameY, frameWidth, frameHeight;
|
||||
|
||||
std::vector<DialogButton*> buttons;
|
||||
BoxLayout* verticalButtonsLayout = nullptr;
|
||||
BoxLayout* horizontalButtonsLayout = nullptr;
|
||||
|
||||
void rebuildButtons();
|
||||
|
||||
unsigned getButtonsHeight();
|
||||
|
||||
bool cancelable = true;
|
||||
|
||||
public:
|
||||
Dialog(std::string text);
|
||||
Dialog(View* contentView);
|
||||
~Dialog();
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
|
||||
View* getDefaultFocus() override;
|
||||
virtual bool onCancel();
|
||||
|
||||
/**
|
||||
* Adds a button to this dialog, with a maximum of three
|
||||
* The position depends on the add order
|
||||
*
|
||||
* Adding a button after the dialog has been opened is
|
||||
* NOT SUPPORTED
|
||||
*/
|
||||
void addButton(std::string label, GenericEvent::Callback cb);
|
||||
|
||||
/**
|
||||
* A cancelable dialog is closed when
|
||||
* the user presses B (defaults to true)
|
||||
*
|
||||
* A dialog without any buttons cannot
|
||||
* be cancelable
|
||||
*/
|
||||
void setCancelable(bool cancelable);
|
||||
|
||||
void open();
|
||||
void close(std::function<void(void)> cb = []() {});
|
||||
|
||||
bool isTranslucent() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
80
lib/borealis/library/include/borealis/dropdown.hpp
Normal file
80
lib/borealis/library/include/borealis/dropdown.hpp
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019-2020 natinusala
|
||||
Copyright (C) 2019-2020 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/event.hpp>
|
||||
#include <borealis/list.hpp>
|
||||
#include <borealis/view.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// Fired when the user has selected a value
|
||||
//
|
||||
// Parameter is either the selected value index
|
||||
// or -1 if the user cancelled
|
||||
//
|
||||
// Assume that the Dropdown is deleted
|
||||
// as soon as this function is called
|
||||
typedef Event<int> ValueSelectedEvent;
|
||||
|
||||
// Allows the user to select between multiple
|
||||
// values
|
||||
// Use Dropdown::open()
|
||||
class Dropdown : public View
|
||||
{
|
||||
private:
|
||||
Dropdown(std::string title, std::vector<std::string> values, ValueSelectedEvent::Callback cb, size_t selected = 0);
|
||||
|
||||
std::string title;
|
||||
|
||||
int valuesCount;
|
||||
|
||||
ValueSelectedEvent valueEvent;
|
||||
|
||||
List* list;
|
||||
Hint* hint;
|
||||
|
||||
float topOffset; // for slide in animation
|
||||
|
||||
protected:
|
||||
unsigned getShowAnimationDuration(ViewAnimation animation) override;
|
||||
|
||||
public:
|
||||
~Dropdown();
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
|
||||
View* getDefaultFocus() override;
|
||||
virtual bool onCancel();
|
||||
void show(std::function<void(void)> cb, bool animate = true, ViewAnimation animation = ViewAnimation::FADE) override;
|
||||
void willAppear(bool resetState = false) override;
|
||||
void willDisappear(bool resetState = false) override;
|
||||
|
||||
static void open(std::string title, std::vector<std::string> values, ValueSelectedEvent::Callback cb, int selected = -1);
|
||||
|
||||
bool isTranslucent() override
|
||||
{
|
||||
return true || View::isTranslucent();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
75
lib/borealis/library/include/borealis/event.hpp
Normal file
75
lib/borealis/library/include/borealis/event.hpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2020 natinusala
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// Simple observer pattern implementation
|
||||
//
|
||||
// Usage:
|
||||
// 1. typedef your event type
|
||||
// 2. create as many events as you want using that type
|
||||
// 3. call subscribe on the events with your observers
|
||||
// 4. call fire when you want to fire the events
|
||||
// it wil return true if at least one subscriber exists
|
||||
// for that event
|
||||
template <typename... Ts>
|
||||
class Event
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(Ts...)> Callback;
|
||||
typedef std::list<Callback> CallbacksList;
|
||||
typedef typename CallbacksList::iterator Subscription;
|
||||
|
||||
Subscription subscribe(Callback cb);
|
||||
void unsubscribe(Subscription subscription);
|
||||
bool fire(Ts... args);
|
||||
|
||||
private:
|
||||
CallbacksList callbacks;
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
typename Event<Ts...>::Subscription Event<Ts...>::subscribe(Event<Ts...>::Callback cb)
|
||||
{
|
||||
this->callbacks.push_back(cb);
|
||||
return --this->callbacks.end();
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
void Event<Ts...>::unsubscribe(Event<Ts...>::Subscription subscription)
|
||||
{
|
||||
this->callbacks.erase(subscription);
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
bool Event<Ts...>::fire(Ts... args)
|
||||
{
|
||||
for (Callback cb : this->callbacks)
|
||||
cb(args...);
|
||||
|
||||
return !this->callbacks.empty();
|
||||
}
|
||||
|
||||
}; // namespace brls
|
||||
3274
lib/borealis/library/include/borealis/extern/glad/glad.h
vendored
Normal file
3274
lib/borealis/library/include/borealis/extern/glad/glad.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
39
lib/borealis/library/include/borealis/extern/libretro-common/boolean.h
vendored
Normal file
39
lib/borealis/library/include/borealis/extern/libretro-common/boolean.h
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (boolean.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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 __LIBRETRO_SDK_BOOLEAN_H
|
||||
#define __LIBRETRO_SDK_BOOLEAN_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1800 && !defined(SN_TARGET_PS3)
|
||||
/* Hack applied for MSVC when compiling in C89 mode as it isn't C99 compliant. */
|
||||
#define bool unsigned char
|
||||
#define true 1
|
||||
#define false 0
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
59
lib/borealis/library/include/borealis/extern/libretro-common/compat/strl.h
vendored
Normal file
59
lib/borealis/library/include/borealis/extern/libretro-common/compat/strl.h
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (strl.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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 __LIBRETRO_SDK_COMPAT_STRL_H
|
||||
#define __LIBRETRO_SDK_COMPAT_STRL_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
|
||||
#include "../../../config.h"
|
||||
#endif
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
#ifdef __MACH__
|
||||
#ifndef HAVE_STRL
|
||||
#define HAVE_STRL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRL
|
||||
/* Avoid possible naming collisions during link since
|
||||
* we prefer to use the actual name. */
|
||||
#define strlcpy(dst, src, size) strlcpy_retro__(dst, src, size)
|
||||
|
||||
#define strlcat(dst, src, size) strlcat_retro__(dst, src, size)
|
||||
|
||||
size_t strlcpy(char *dest, const char *source, size_t size);
|
||||
size_t strlcat(char *dest, const char *source, size_t size);
|
||||
|
||||
#endif
|
||||
|
||||
char *strldup(const char *s, size_t n);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
67
lib/borealis/library/include/borealis/extern/libretro-common/encodings/utf.h
vendored
Normal file
67
lib/borealis/library/include/borealis/extern/libretro-common/encodings/utf.h
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (utf.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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 _LIBRETRO_ENCODINGS_UTF_H
|
||||
#define _LIBRETRO_ENCODINGS_UTF_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <boolean.h>
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
enum CodePage
|
||||
{
|
||||
CODEPAGE_LOCAL = 0, /* CP_ACP */
|
||||
CODEPAGE_UTF8 = 65001 /* CP_UTF8 */
|
||||
};
|
||||
|
||||
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
||||
const char *in, size_t in_size);
|
||||
|
||||
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
|
||||
const uint16_t *in, size_t in_size);
|
||||
|
||||
size_t utf8len(const char *string);
|
||||
|
||||
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars);
|
||||
|
||||
const char *utf8skip(const char *str, size_t chars);
|
||||
|
||||
uint32_t utf8_walk(const char **string);
|
||||
|
||||
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len);
|
||||
|
||||
char* utf8_to_local_string_alloc(const char *str);
|
||||
|
||||
char* local_to_utf8_string_alloc(const char *str);
|
||||
|
||||
wchar_t* utf8_to_utf16_string_alloc(const char *str);
|
||||
|
||||
char* utf16_to_utf8_string_alloc(const wchar_t *str);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
75
lib/borealis/library/include/borealis/extern/libretro-common/features/features_cpu.h
vendored
Normal file
75
lib/borealis/library/include/borealis/extern/libretro-common/features/features_cpu.h
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (features_cpu.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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 _LIBRETRO_SDK_CPU_INFO_H
|
||||
#define _LIBRETRO_SDK_CPU_INFO_H
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libretro.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* cpu_features_get_perf_counter:
|
||||
*
|
||||
* Gets performance counter.
|
||||
*
|
||||
* Returns: performance counter.
|
||||
**/
|
||||
retro_perf_tick_t cpu_features_get_perf_counter(void);
|
||||
|
||||
/**
|
||||
* cpu_features_get_time_usec:
|
||||
*
|
||||
* Gets time in microseconds, from an undefined epoch.
|
||||
* The epoch may change between computers or across reboots.
|
||||
*
|
||||
* Returns: time in microseconds
|
||||
**/
|
||||
retro_time_t cpu_features_get_time_usec(void);
|
||||
|
||||
/**
|
||||
* cpu_features_get:
|
||||
*
|
||||
* Gets CPU features.
|
||||
*
|
||||
* Returns: bitmask of all CPU features available.
|
||||
**/
|
||||
uint64_t cpu_features_get(void);
|
||||
|
||||
/**
|
||||
* cpu_features_get_core_amount:
|
||||
*
|
||||
* Gets the amount of available CPU cores.
|
||||
*
|
||||
* Returns: amount of CPU cores available.
|
||||
**/
|
||||
unsigned cpu_features_get_core_amount(void);
|
||||
|
||||
void cpu_features_get_model_name(char *name, int len);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
2537
lib/borealis/library/include/borealis/extern/libretro-common/libretro.h
vendored
Normal file
2537
lib/borealis/library/include/borealis/extern/libretro-common/libretro.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
37
lib/borealis/library/include/borealis/extern/libretro-common/retro_assert.h
vendored
Normal file
37
lib/borealis/library/include/borealis/extern/libretro-common/retro_assert.h
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_assert.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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 __RETRO_ASSERT_H
|
||||
#define __RETRO_ASSERT_H
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef RARCH_INTERNAL
|
||||
#include <stdio.h>
|
||||
#define retro_assert(cond) do { \
|
||||
if (!(cond)) { printf("Assertion failed at %s:%d.\n", __FILE__, __LINE__); abort(); } \
|
||||
} while(0)
|
||||
#else
|
||||
#define retro_assert(cond) assert(cond)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
117
lib/borealis/library/include/borealis/extern/libretro-common/retro_common_api.h
vendored
Normal file
117
lib/borealis/library/include/borealis/extern/libretro-common/retro_common_api.h
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_common_api.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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 _LIBRETRO_COMMON_RETRO_COMMON_API_H
|
||||
#define _LIBRETRO_COMMON_RETRO_COMMON_API_H
|
||||
|
||||
/*
|
||||
This file is designed to normalize the libretro-common compiling environment
|
||||
for public API headers. This should be leaner than a normal compiling environment,
|
||||
since it gets #included into other project's sources.
|
||||
*/
|
||||
|
||||
/* ------------------------------------ */
|
||||
|
||||
/*
|
||||
Ordinarily we want to put #ifdef __cplusplus extern "C" in C library
|
||||
headers to enable them to get used by c++ sources.
|
||||
However, we want to support building this library as C++ as well, so a
|
||||
special technique is called for.
|
||||
*/
|
||||
|
||||
#define RETRO_BEGIN_DECLS
|
||||
#define RETRO_END_DECLS
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#ifdef CXX_BUILD
|
||||
/* build wants everything to be built as c++, so no extern "C" */
|
||||
#else
|
||||
#undef RETRO_BEGIN_DECLS
|
||||
#undef RETRO_END_DECLS
|
||||
#define RETRO_BEGIN_DECLS extern "C" {
|
||||
#define RETRO_END_DECLS }
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
/* header is included by a C source file, so no extern "C" */
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
IMO, this non-standard ssize_t should not be used.
|
||||
However, it's a good example of how to handle something like this.
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
#ifndef HAVE_SSIZE_T
|
||||
#define HAVE_SSIZE_T
|
||||
#if defined(_WIN64)
|
||||
typedef __int64 ssize_t;
|
||||
#elif defined(_WIN32)
|
||||
typedef int ssize_t;
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(__MACH__)
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER >= 1800
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
#ifndef PRId64
|
||||
#define PRId64 "I64d"
|
||||
#define PRIu64 "I64u"
|
||||
#define PRIuPTR "Iu"
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
/* C++11 says this one isn't needed, but apparently (some versions of) mingw require it anyways */
|
||||
/* https://stackoverflow.com/questions/8132399/how-to-printf-uint64-t-fails-with-spurious-trailing-in-format */
|
||||
/* https://github.com/libretro/RetroArch/issues/6009 */
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
#ifndef PRId64
|
||||
#error "inttypes.h is being screwy"
|
||||
#endif
|
||||
#define STRING_REP_INT64 "%" PRId64
|
||||
#define STRING_REP_UINT64 "%" PRIu64
|
||||
#define STRING_REP_USIZE "%" PRIuPTR
|
||||
|
||||
/*
|
||||
I would like to see retro_inline.h moved in here; possibly boolean too.
|
||||
|
||||
rationale: these are used in public APIs, and it is easier to find problems
|
||||
and write code that works the first time portably when theyre included uniformly
|
||||
than to do the analysis from scratch each time you think you need it, for each feature.
|
||||
|
||||
Moreover it helps force you to make hard decisions: if you EVER bring in boolean.h,
|
||||
then you should pay the price everywhere, so you can see how much grief it will cause.
|
||||
|
||||
Of course, another school of thought is that you should do as little damage as possible
|
||||
in as few places as possible...
|
||||
*/
|
||||
|
||||
/* _LIBRETRO_COMMON_RETRO_COMMON_API_H */
|
||||
#endif
|
||||
39
lib/borealis/library/include/borealis/extern/libretro-common/retro_inline.h
vendored
Normal file
39
lib/borealis/library/include/borealis/extern/libretro-common/retro_inline.h
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_inline.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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 __LIBRETRO_SDK_INLINE_H
|
||||
#define __LIBRETRO_SDK_INLINE_H
|
||||
|
||||
#ifndef INLINE
|
||||
|
||||
#if defined(_WIN32) || defined(__INTEL_COMPILER)
|
||||
#define INLINE __inline
|
||||
#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
|
||||
#define INLINE inline
|
||||
#elif defined(__GNUC__)
|
||||
#define INLINE __inline__
|
||||
#else
|
||||
#define INLINE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
94
lib/borealis/library/include/borealis/extern/libretro-common/retro_math.h
vendored
Normal file
94
lib/borealis/library/include/borealis/extern/libretro-common/retro_math.h
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_math.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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 _LIBRETRO_COMMON_MATH_H
|
||||
#define _LIBRETRO_COMMON_MATH_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#elif defined(_WIN32) && defined(_XBOX)
|
||||
#include <Xtl.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <compat/msvc.h>
|
||||
#endif
|
||||
#include <retro_inline.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#if !defined(USE_MATH_DEFINES)
|
||||
#define M_PI 3.14159265358979323846264338327
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* next_pow2:
|
||||
* @v : initial value
|
||||
*
|
||||
* Get next power of 2 value based on initial value.
|
||||
*
|
||||
* Returns: next power of 2 value (derived from @v).
|
||||
**/
|
||||
static INLINE uint32_t next_pow2(uint32_t v)
|
||||
{
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
v++;
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* prev_pow2:
|
||||
* @v : initial value
|
||||
*
|
||||
* Get previous power of 2 value based on initial value.
|
||||
*
|
||||
* Returns: previous power of 2 value (derived from @v).
|
||||
**/
|
||||
static INLINE uint32_t prev_pow2(uint32_t v)
|
||||
{
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
return v - (v >> 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
182
lib/borealis/library/include/borealis/extern/libretro-common/retro_miscellaneous.h
vendored
Normal file
182
lib/borealis/library/include/borealis/extern/libretro-common/retro_miscellaneous.h
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_miscellaneous.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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 __RARCH_MISCELLANEOUS_H
|
||||
#define __RARCH_MISCELLANEOUS_H
|
||||
|
||||
#define RARCH_MAX_SUBSYSTEMS 10
|
||||
#define RARCH_MAX_SUBSYSTEM_ROMS 10
|
||||
|
||||
#include <stdint.h>
|
||||
#include <boolean.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#elif defined(_WIN32) && defined(_XBOX)
|
||||
#include <Xtl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__CELLOS_LV2__)
|
||||
#include <sys/fs_external.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <compat/msvc.h>
|
||||
#endif
|
||||
|
||||
static INLINE void bits_or_bits(uint32_t *a, uint32_t *b, uint32_t count)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < count;i++)
|
||||
a[i] |= b[i];
|
||||
}
|
||||
|
||||
static INLINE void bits_clear_bits(uint32_t *a, uint32_t *b, uint32_t count)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < count;i++)
|
||||
a[i] &= ~b[i];
|
||||
}
|
||||
|
||||
static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (ptr[i] != 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef PATH_MAX_LENGTH
|
||||
#if defined(__CELLOS_LV2__)
|
||||
#define PATH_MAX_LENGTH CELL_FS_MAX_FS_PATH_LENGTH
|
||||
#elif defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS)
|
||||
#define PATH_MAX_LENGTH 512
|
||||
#else
|
||||
#define PATH_MAX_LENGTH 4096
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
#define BITS_GET_ELEM(a, i) ((a).data[i])
|
||||
#define BITS_GET_ELEM_PTR(a, i) ((a)->data[i])
|
||||
|
||||
#define BIT_SET(a, bit) ((a)[(bit) >> 3] |= (1 << ((bit) & 7)))
|
||||
#define BIT_CLEAR(a, bit) ((a)[(bit) >> 3] &= ~(1 << ((bit) & 7)))
|
||||
#define BIT_GET(a, bit) (((a)[(bit) >> 3] >> ((bit) & 7)) & 1)
|
||||
|
||||
#define BIT16_SET(a, bit) ((a) |= (1 << ((bit) & 15)))
|
||||
#define BIT16_CLEAR(a, bit) ((a) &= ~(1 << ((bit) & 15)))
|
||||
#define BIT16_GET(a, bit) (((a) >> ((bit) & 15)) & 1)
|
||||
#define BIT16_CLEAR_ALL(a) ((a) = 0)
|
||||
|
||||
#define BIT32_SET(a, bit) ((a) |= (1 << ((bit) & 31)))
|
||||
#define BIT32_CLEAR(a, bit) ((a) &= ~(1 << ((bit) & 31)))
|
||||
#define BIT32_GET(a, bit) (((a) >> ((bit) & 31)) & 1)
|
||||
#define BIT32_CLEAR_ALL(a) ((a) = 0)
|
||||
|
||||
#define BIT64_SET(a, bit) ((a) |= (UINT64_C(1) << ((bit) & 63)))
|
||||
#define BIT64_CLEAR(a, bit) ((a) &= ~(UINT64_C(1) << ((bit) & 63)))
|
||||
#define BIT64_GET(a, bit) (((a) >> ((bit) & 63)) & 1)
|
||||
#define BIT64_CLEAR_ALL(a) ((a) = 0)
|
||||
|
||||
#define BIT128_SET(a, bit) ((a).data[(bit) >> 5] |= (1 << ((bit) & 31)))
|
||||
#define BIT128_CLEAR(a, bit) ((a).data[(bit) >> 5] &= ~(1 << ((bit) & 31)))
|
||||
#define BIT128_GET(a, bit) (((a).data[(bit) >> 5] >> ((bit) & 31)) & 1)
|
||||
#define BIT128_CLEAR_ALL(a) memset(&(a), 0, sizeof(a))
|
||||
|
||||
#define BIT128_SET_PTR(a, bit) BIT128_SET(*a, bit)
|
||||
#define BIT128_CLEAR_PTR(a, bit) BIT128_CLEAR(*a, bit)
|
||||
#define BIT128_GET_PTR(a, bit) BIT128_GET(*a, bit)
|
||||
#define BIT128_CLEAR_ALL_PTR(a) BIT128_CLEAR_ALL(*a)
|
||||
|
||||
#define BIT256_SET(a, bit) BIT128_SET(a, bit)
|
||||
#define BIT256_CLEAR(a, bit) BIT128_CLEAR(a, bit)
|
||||
#define BIT256_GET(a, bit) BIT128_GET(a, bit)
|
||||
#define BIT256_CLEAR_ALL(a) BIT128_CLEAR_ALL(a)
|
||||
|
||||
#define BIT256_SET_PTR(a, bit) BIT256_SET(*a, bit)
|
||||
#define BIT256_CLEAR_PTR(a, bit) BIT256_CLEAR(*a, bit)
|
||||
#define BIT256_GET_PTR(a, bit) BIT256_GET(*a, bit)
|
||||
#define BIT256_CLEAR_ALL_PTR(a) BIT256_CLEAR_ALL(*a)
|
||||
|
||||
#define BITS_COPY16_PTR(a,bits) \
|
||||
{ \
|
||||
BIT128_CLEAR_ALL_PTR(a); \
|
||||
BITS_GET_ELEM_PTR(a, 0) = (bits) & 0xffff; \
|
||||
}
|
||||
|
||||
#define BITS_COPY32_PTR(a,bits) \
|
||||
{ \
|
||||
BIT128_CLEAR_ALL_PTR(a); \
|
||||
BITS_GET_ELEM_PTR(a, 0) = (bits); \
|
||||
}
|
||||
|
||||
/* Helper macros and struct to keep track of many booleans. */
|
||||
/* This struct has 256 bits. */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t data[8];
|
||||
} retro_bits_t;
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef _WIN64
|
||||
# define PRI_SIZET PRIu64
|
||||
# else
|
||||
# if _MSC_VER == 1800
|
||||
# define PRI_SIZET PRIu32
|
||||
# else
|
||||
# define PRI_SIZET "u"
|
||||
# endif
|
||||
# endif
|
||||
#elif PS2
|
||||
# define PRI_SIZET "u"
|
||||
#else
|
||||
# if (SIZE_MAX == 0xFFFF)
|
||||
# define PRI_SIZET "hu"
|
||||
# elif (SIZE_MAX == 0xFFFFFFFF)
|
||||
# define PRI_SIZET "u"
|
||||
# elif (SIZE_MAX == 0xFFFFFFFFFFFFFFFF)
|
||||
# define PRI_SIZET "lu"
|
||||
# else
|
||||
# error PRI_SIZET: unknown SIZE_MAX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
116
lib/borealis/library/include/borealis/extern/libretro-common/retro_timers.h
vendored
Normal file
116
lib/borealis/library/include/borealis/extern/libretro-common/retro_timers.h
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_timers.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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 __LIBRETRO_COMMON_TIMERS_H
|
||||
#define __LIBRETRO_COMMON_TIMERS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
#include <sys/timer.h>
|
||||
#elif defined(XENON)
|
||||
#include <time/time.h>
|
||||
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
|
||||
#include <unistd.h>
|
||||
#elif defined(WIIU)
|
||||
#include <wiiu/os/thread.h>
|
||||
#elif defined(PSP)
|
||||
#include <pspthreadman.h>
|
||||
#elif defined(VITA)
|
||||
#include <psp2/kernel/threadmgr.h>
|
||||
#elif defined(PS2)
|
||||
#include <SDL/SDL_timer.h>
|
||||
#elif defined(_3DS)
|
||||
#include <3ds.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#elif defined(_WIN32) && defined(_XBOX)
|
||||
#include <Xtl.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <compat/msvc.h>
|
||||
#endif
|
||||
#include <retro_inline.h>
|
||||
|
||||
#ifdef DJGPP
|
||||
#define timespec timeval
|
||||
#define tv_nsec tv_usec
|
||||
#include <unistd.h>
|
||||
|
||||
extern int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
|
||||
|
||||
static int nanosleepDOS(const struct timespec *rqtp, struct timespec *rmtp)
|
||||
{
|
||||
usleep(1000000 * rqtp->tv_sec + rqtp->tv_nsec / 1000);
|
||||
|
||||
if (rmtp)
|
||||
rmtp->tv_sec = rmtp->tv_nsec=0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define nanosleep nanosleepDOS
|
||||
#endif
|
||||
|
||||
/**
|
||||
* retro_sleep:
|
||||
* @msec : amount in milliseconds to sleep
|
||||
*
|
||||
* Sleeps for a specified amount of milliseconds (@msec).
|
||||
**/
|
||||
static INLINE void retro_sleep(unsigned msec)
|
||||
{
|
||||
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
sys_timer_usleep(1000 * msec);
|
||||
#elif defined(PSP) || defined(VITA)
|
||||
sceKernelDelayThread(1000 * msec);
|
||||
#elif defined(PS2)
|
||||
SDL_Delay(msec);
|
||||
#elif defined(_3DS)
|
||||
svcSleepThread(1000000 * (s64)msec);
|
||||
#elif defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
|
||||
SleepEx(msec, FALSE);
|
||||
#elif defined(_WIN32)
|
||||
Sleep(msec);
|
||||
#elif defined(XENON)
|
||||
udelay(1000 * msec);
|
||||
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
|
||||
usleep(1000 * msec);
|
||||
#elif defined(WIIU)
|
||||
OSSleepTicks(ms_to_ticks(msec));
|
||||
#else
|
||||
struct timespec tv = {0};
|
||||
tv.tv_sec = msec / 1000;
|
||||
tv.tv_nsec = (msec % 1000) * 1000000;
|
||||
nanosleep(&tv, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
111
lib/borealis/library/include/borealis/extern/libretro-common/streams/file_stream.h
vendored
Normal file
111
lib/borealis/library/include/borealis/extern/libretro-common/streams/file_stream.h
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (file_stream.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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 __LIBRETRO_SDK_FILE_STREAM_H
|
||||
#define __LIBRETRO_SDK_FILE_STREAM_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <libretro.h>
|
||||
#include <retro_common_api.h>
|
||||
#include <retro_inline.h>
|
||||
#include <boolean.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define FILESTREAM_REQUIRED_VFS_VERSION 2
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
typedef struct RFILE RFILE;
|
||||
|
||||
#define FILESTREAM_REQUIRED_VFS_VERSION 2
|
||||
|
||||
void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info);
|
||||
|
||||
int64_t filestream_get_size(RFILE *stream);
|
||||
|
||||
int64_t filestream_truncate(RFILE *stream, int64_t length);
|
||||
|
||||
/**
|
||||
* filestream_open:
|
||||
* @path : path to file
|
||||
* @mode : file mode to use when opening (read/write)
|
||||
* @bufsize : optional buffer size (-1 or 0 to use default)
|
||||
*
|
||||
* Opens a file for reading or writing, depending on the requested mode.
|
||||
* Returns a pointer to an RFILE if opened successfully, otherwise NULL.
|
||||
**/
|
||||
RFILE *filestream_open(const char *path, unsigned mode, unsigned hints);
|
||||
|
||||
int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position);
|
||||
|
||||
int64_t filestream_read(RFILE *stream, void *data, int64_t len);
|
||||
|
||||
int64_t filestream_write(RFILE *stream, const void *data, int64_t len);
|
||||
|
||||
int64_t filestream_tell(RFILE *stream);
|
||||
|
||||
void filestream_rewind(RFILE *stream);
|
||||
|
||||
int filestream_close(RFILE *stream);
|
||||
|
||||
int64_t filestream_read_file(const char *path, void **buf, int64_t *len);
|
||||
|
||||
char *filestream_gets(RFILE *stream, char *s, size_t len);
|
||||
|
||||
int filestream_getc(RFILE *stream);
|
||||
|
||||
int filestream_scanf(RFILE *stream, const char* format, ...);
|
||||
|
||||
int filestream_eof(RFILE *stream);
|
||||
|
||||
bool filestream_write_file(const char *path, const void *data, int64_t size);
|
||||
|
||||
int filestream_putc(RFILE *stream, int c);
|
||||
|
||||
int filestream_vprintf(RFILE *stream, const char* format, va_list args);
|
||||
|
||||
int filestream_printf(RFILE *stream, const char* format, ...);
|
||||
|
||||
int filestream_error(RFILE *stream);
|
||||
|
||||
int filestream_flush(RFILE *stream);
|
||||
|
||||
int filestream_delete(const char *path);
|
||||
|
||||
int filestream_rename(const char *old_path, const char *new_path);
|
||||
|
||||
const char *filestream_get_path(RFILE *stream);
|
||||
|
||||
bool filestream_exists(const char *path);
|
||||
|
||||
char *filestream_getline(RFILE *stream);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
134
lib/borealis/library/include/borealis/extern/libretro-common/string/stdstring.h
vendored
Normal file
134
lib/borealis/library/include/borealis/extern/libretro-common/string/stdstring.h
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (stdstring.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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 __LIBRETRO_SDK_STDSTRING_H
|
||||
#define __LIBRETRO_SDK_STDSTRING_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <boolean.h>
|
||||
|
||||
#include <retro_common_api.h>
|
||||
#include <retro_inline.h>
|
||||
#include <compat/strl.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
static INLINE bool string_is_empty(const char *data)
|
||||
{
|
||||
return !data || (*data == '\0');
|
||||
}
|
||||
|
||||
static INLINE bool string_is_equal(const char *a, const char *b)
|
||||
{
|
||||
return (a && b) ? !strcmp(a, b) : false;
|
||||
}
|
||||
|
||||
#define STRLEN_CONST(x) ((sizeof((x))-1))
|
||||
|
||||
#define string_is_not_equal(a, b) !string_is_equal((a), (b))
|
||||
|
||||
#define string_add_pair_open(s, size) strlcat((s), " (", (size))
|
||||
#define string_add_pair_close(s, size) strlcat((s), ")", (size))
|
||||
#define string_add_bracket_open(s, size) strlcat((s), "{", (size))
|
||||
#define string_add_bracket_close(s, size) strlcat((s), "}", (size))
|
||||
#define string_add_single_quote(s, size) strlcat((s), "'", (size))
|
||||
#define string_add_quote(s, size) strlcat((s), "\"", (size))
|
||||
#define string_add_colon(s, size) strlcat((s), ":", (size))
|
||||
#define string_add_glob_open(s, size) strlcat((s), "glob('*", (size))
|
||||
#define string_add_glob_close(s, size) strlcat((s), "*')", (size))
|
||||
|
||||
#define string_is_not_equal_fast(a, b, size) (memcmp(a, b, size) != 0)
|
||||
#define string_is_equal_fast(a, b, size) (memcmp(a, b, size) == 0)
|
||||
|
||||
static INLINE void string_add_between_pairs(char *s, const char *str,
|
||||
size_t size)
|
||||
{
|
||||
string_add_pair_open(s, size);
|
||||
strlcat(s, str, size);
|
||||
string_add_pair_close(s, size);
|
||||
}
|
||||
|
||||
static INLINE bool string_is_equal_case_insensitive(const char *a,
|
||||
const char *b)
|
||||
{
|
||||
int result = 0;
|
||||
const unsigned char *p1 = (const unsigned char*)a;
|
||||
const unsigned char *p2 = (const unsigned char*)b;
|
||||
|
||||
if (!a || !b)
|
||||
return false;
|
||||
if (p1 == p2)
|
||||
return true;
|
||||
|
||||
while ((result = tolower (*p1) - tolower (*p2++)) == 0)
|
||||
if (*p1++ == '\0')
|
||||
break;
|
||||
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
static INLINE bool string_is_equal_noncase(const char *a, const char *b)
|
||||
{
|
||||
int result = 0;
|
||||
const unsigned char *p1 = (const unsigned char*)a;
|
||||
const unsigned char *p2 = (const unsigned char*)b;
|
||||
|
||||
if (!a || !b)
|
||||
return false;
|
||||
if (p1 == p2)
|
||||
return false;
|
||||
|
||||
while ((result = tolower (*p1) - tolower (*p2++)) == 0)
|
||||
if (*p1++ == '\0')
|
||||
break;
|
||||
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
char *string_to_upper(char *s);
|
||||
|
||||
char *string_to_lower(char *s);
|
||||
|
||||
char *string_ucwords(char *s);
|
||||
|
||||
char *string_replace_substring(const char *in, const char *pattern,
|
||||
const char *by);
|
||||
|
||||
/* Remove leading whitespaces */
|
||||
char *string_trim_whitespace_left(char *const s);
|
||||
|
||||
/* Remove trailing whitespaces */
|
||||
char *string_trim_whitespace_right(char *const s);
|
||||
|
||||
/* Remove leading and trailing whitespaces */
|
||||
char *string_trim_whitespace(char *const s);
|
||||
|
||||
/* max_lines == 0 means no limit */
|
||||
char *word_wrap(char *buffer, const char *string,
|
||||
int line_width, bool unicode, unsigned max_lines);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
18
lib/borealis/library/include/borealis/extern/nanovg/LICENSE.txt
vendored
Normal file
18
lib/borealis/library/include/borealis/extern/nanovg/LICENSE.txt
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
Copyright (c) 2013 Mikko Mononen memon@inside.org
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
1768
lib/borealis/library/include/borealis/extern/nanovg/fontstash.h
vendored
Normal file
1768
lib/borealis/library/include/borealis/extern/nanovg/fontstash.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
685
lib/borealis/library/include/borealis/extern/nanovg/nanovg.h
vendored
Normal file
685
lib/borealis/library/include/borealis/extern/nanovg/nanovg.h
vendored
Normal file
@@ -0,0 +1,685 @@
|
||||
//
|
||||
// Copyright (c) 2013 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#ifndef NANOVG_H
|
||||
#define NANOVG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NVG_PI 3.14159265358979323846264338327f
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union
|
||||
#endif
|
||||
|
||||
typedef struct NVGcontext NVGcontext;
|
||||
|
||||
struct NVGcolor {
|
||||
union {
|
||||
float rgba[4];
|
||||
struct {
|
||||
float r,g,b,a;
|
||||
};
|
||||
};
|
||||
};
|
||||
typedef struct NVGcolor NVGcolor;
|
||||
|
||||
struct NVGpaint {
|
||||
float xform[6];
|
||||
float extent[2];
|
||||
float radius;
|
||||
float feather;
|
||||
NVGcolor innerColor;
|
||||
NVGcolor outerColor;
|
||||
int image;
|
||||
};
|
||||
typedef struct NVGpaint NVGpaint;
|
||||
|
||||
enum NVGwinding {
|
||||
NVG_CCW = 1, // Winding for solid shapes
|
||||
NVG_CW = 2, // Winding for holes
|
||||
};
|
||||
|
||||
enum NVGsolidity {
|
||||
NVG_SOLID = 1, // CCW
|
||||
NVG_HOLE = 2, // CW
|
||||
};
|
||||
|
||||
enum NVGlineCap {
|
||||
NVG_BUTT,
|
||||
NVG_ROUND,
|
||||
NVG_SQUARE,
|
||||
NVG_BEVEL,
|
||||
NVG_MITER,
|
||||
};
|
||||
|
||||
enum NVGalign {
|
||||
// Horizontal align
|
||||
NVG_ALIGN_LEFT = 1<<0, // Default, align text horizontally to left.
|
||||
NVG_ALIGN_CENTER = 1<<1, // Align text horizontally to center.
|
||||
NVG_ALIGN_RIGHT = 1<<2, // Align text horizontally to right.
|
||||
// Vertical align
|
||||
NVG_ALIGN_TOP = 1<<3, // Align text vertically to top.
|
||||
NVG_ALIGN_MIDDLE = 1<<4, // Align text vertically to middle.
|
||||
NVG_ALIGN_BOTTOM = 1<<5, // Align text vertically to bottom.
|
||||
NVG_ALIGN_BASELINE = 1<<6, // Default, align text vertically to baseline.
|
||||
};
|
||||
|
||||
enum NVGblendFactor {
|
||||
NVG_ZERO = 1<<0,
|
||||
NVG_ONE = 1<<1,
|
||||
NVG_SRC_COLOR = 1<<2,
|
||||
NVG_ONE_MINUS_SRC_COLOR = 1<<3,
|
||||
NVG_DST_COLOR = 1<<4,
|
||||
NVG_ONE_MINUS_DST_COLOR = 1<<5,
|
||||
NVG_SRC_ALPHA = 1<<6,
|
||||
NVG_ONE_MINUS_SRC_ALPHA = 1<<7,
|
||||
NVG_DST_ALPHA = 1<<8,
|
||||
NVG_ONE_MINUS_DST_ALPHA = 1<<9,
|
||||
NVG_SRC_ALPHA_SATURATE = 1<<10,
|
||||
};
|
||||
|
||||
enum NVGcompositeOperation {
|
||||
NVG_SOURCE_OVER,
|
||||
NVG_SOURCE_IN,
|
||||
NVG_SOURCE_OUT,
|
||||
NVG_ATOP,
|
||||
NVG_DESTINATION_OVER,
|
||||
NVG_DESTINATION_IN,
|
||||
NVG_DESTINATION_OUT,
|
||||
NVG_DESTINATION_ATOP,
|
||||
NVG_LIGHTER,
|
||||
NVG_COPY,
|
||||
NVG_XOR,
|
||||
};
|
||||
|
||||
struct NVGcompositeOperationState {
|
||||
int srcRGB;
|
||||
int dstRGB;
|
||||
int srcAlpha;
|
||||
int dstAlpha;
|
||||
};
|
||||
typedef struct NVGcompositeOperationState NVGcompositeOperationState;
|
||||
|
||||
struct NVGglyphPosition {
|
||||
const char* str; // Position of the glyph in the input string.
|
||||
float x; // The x-coordinate of the logical glyph position.
|
||||
float minx, maxx; // The bounds of the glyph shape.
|
||||
};
|
||||
typedef struct NVGglyphPosition NVGglyphPosition;
|
||||
|
||||
struct NVGtextRow {
|
||||
const char* start; // Pointer to the input text where the row starts.
|
||||
const char* end; // Pointer to the input text where the row ends (one past the last character).
|
||||
const char* next; // Pointer to the beginning of the next row.
|
||||
float width; // Logical width of the row.
|
||||
float minx, maxx; // Actual bounds of the row. Logical with and bounds can differ because of kerning and some parts over extending.
|
||||
};
|
||||
typedef struct NVGtextRow NVGtextRow;
|
||||
|
||||
enum NVGimageFlags {
|
||||
NVG_IMAGE_GENERATE_MIPMAPS = 1<<0, // Generate mipmaps during creation of the image.
|
||||
NVG_IMAGE_REPEATX = 1<<1, // Repeat image in X direction.
|
||||
NVG_IMAGE_REPEATY = 1<<2, // Repeat image in Y direction.
|
||||
NVG_IMAGE_FLIPY = 1<<3, // Flips (inverses) image in Y direction when rendered.
|
||||
NVG_IMAGE_PREMULTIPLIED = 1<<4, // Image data has premultiplied alpha.
|
||||
NVG_IMAGE_NEAREST = 1<<5, // Image interpolation is Nearest instead Linear
|
||||
};
|
||||
|
||||
// Begin drawing a new frame
|
||||
// Calls to nanovg drawing API should be wrapped in nvgBeginFrame() & nvgEndFrame()
|
||||
// nvgBeginFrame() defines the size of the window to render to in relation currently
|
||||
// set viewport (i.e. glViewport on GL backends). Device pixel ration allows to
|
||||
// control the rendering on Hi-DPI devices.
|
||||
// For example, GLFW returns two dimension for an opened window: window size and
|
||||
// frame buffer size. In that case you would set windowWidth/Height to the window size
|
||||
// devicePixelRatio to: frameBufferWidth / windowWidth.
|
||||
void nvgBeginFrame(NVGcontext* ctx, float windowWidth, float windowHeight, float devicePixelRatio);
|
||||
|
||||
// Cancels drawing the current frame.
|
||||
void nvgCancelFrame(NVGcontext* ctx);
|
||||
|
||||
// Ends drawing flushing remaining render state.
|
||||
void nvgEndFrame(NVGcontext* ctx);
|
||||
|
||||
//
|
||||
// Composite operation
|
||||
//
|
||||
// The composite operations in NanoVG are modeled after HTML Canvas API, and
|
||||
// the blend func is based on OpenGL (see corresponding manuals for more info).
|
||||
// The colors in the blending state have premultiplied alpha.
|
||||
|
||||
// Sets the composite operation. The op parameter should be one of NVGcompositeOperation.
|
||||
void nvgGlobalCompositeOperation(NVGcontext* ctx, int op);
|
||||
|
||||
// Sets the composite operation with custom pixel arithmetic. The parameters should be one of NVGblendFactor.
|
||||
void nvgGlobalCompositeBlendFunc(NVGcontext* ctx, int sfactor, int dfactor);
|
||||
|
||||
// Sets the composite operation with custom pixel arithmetic for RGB and alpha components separately. The parameters should be one of NVGblendFactor.
|
||||
void nvgGlobalCompositeBlendFuncSeparate(NVGcontext* ctx, int srcRGB, int dstRGB, int srcAlpha, int dstAlpha);
|
||||
|
||||
//
|
||||
// Color utils
|
||||
//
|
||||
// Colors in NanoVG are stored as unsigned ints in ABGR format.
|
||||
|
||||
// Returns a color value from red, green, blue values. Alpha will be set to 255 (1.0f).
|
||||
NVGcolor nvgRGB(unsigned char r, unsigned char g, unsigned char b);
|
||||
|
||||
// Returns a color value from red, green, blue values. Alpha will be set to 1.0f.
|
||||
NVGcolor nvgRGBf(float r, float g, float b);
|
||||
|
||||
|
||||
// Returns a color value from red, green, blue and alpha values.
|
||||
NVGcolor nvgRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
|
||||
|
||||
// Returns a color value from red, green, blue and alpha values.
|
||||
NVGcolor nvgRGBAf(float r, float g, float b, float a);
|
||||
|
||||
|
||||
// Linearly interpolates from color c0 to c1, and returns resulting color value.
|
||||
NVGcolor nvgLerpRGBA(NVGcolor c0, NVGcolor c1, float u);
|
||||
|
||||
// Sets transparency of a color value.
|
||||
NVGcolor nvgTransRGBA(NVGcolor c0, unsigned char a);
|
||||
|
||||
// Sets transparency of a color value.
|
||||
NVGcolor nvgTransRGBAf(NVGcolor c0, float a);
|
||||
|
||||
// Returns color value specified by hue, saturation and lightness.
|
||||
// HSL values are all in range [0..1], alpha will be set to 255.
|
||||
NVGcolor nvgHSL(float h, float s, float l);
|
||||
|
||||
// Returns color value specified by hue, saturation and lightness and alpha.
|
||||
// HSL values are all in range [0..1], alpha in range [0..255]
|
||||
NVGcolor nvgHSLA(float h, float s, float l, unsigned char a);
|
||||
|
||||
//
|
||||
// State Handling
|
||||
//
|
||||
// NanoVG contains state which represents how paths will be rendered.
|
||||
// The state contains transform, fill and stroke styles, text and font styles,
|
||||
// and scissor clipping.
|
||||
|
||||
// Pushes and saves the current render state into a state stack.
|
||||
// A matching nvgRestore() must be used to restore the state.
|
||||
void nvgSave(NVGcontext* ctx);
|
||||
|
||||
// Pops and restores current render state.
|
||||
void nvgRestore(NVGcontext* ctx);
|
||||
|
||||
// Resets current render state to default values. Does not affect the render state stack.
|
||||
void nvgReset(NVGcontext* ctx);
|
||||
|
||||
//
|
||||
// Render styles
|
||||
//
|
||||
// Fill and stroke render style can be either a solid color or a paint which is a gradient or a pattern.
|
||||
// Solid color is simply defined as a color value, different kinds of paints can be created
|
||||
// using nvgLinearGradient(), nvgBoxGradient(), nvgRadialGradient() and nvgImagePattern().
|
||||
//
|
||||
// Current render style can be saved and restored using nvgSave() and nvgRestore().
|
||||
|
||||
// Sets whether to draw antialias for nvgStroke() and nvgFill(). It's enabled by default.
|
||||
void nvgShapeAntiAlias(NVGcontext* ctx, int enabled);
|
||||
|
||||
// Sets current stroke style to a solid color.
|
||||
void nvgStrokeColor(NVGcontext* ctx, NVGcolor color);
|
||||
|
||||
// Sets current stroke style to a paint, which can be a one of the gradients or a pattern.
|
||||
void nvgStrokePaint(NVGcontext* ctx, NVGpaint paint);
|
||||
|
||||
// Sets current fill style to a solid color.
|
||||
void nvgFillColor(NVGcontext* ctx, NVGcolor color);
|
||||
|
||||
// Sets current fill style to a paint, which can be a one of the gradients or a pattern.
|
||||
void nvgFillPaint(NVGcontext* ctx, NVGpaint paint);
|
||||
|
||||
// Sets the miter limit of the stroke style.
|
||||
// Miter limit controls when a sharp corner is beveled.
|
||||
void nvgMiterLimit(NVGcontext* ctx, float limit);
|
||||
|
||||
// Sets the stroke width of the stroke style.
|
||||
void nvgStrokeWidth(NVGcontext* ctx, float size);
|
||||
|
||||
// Sets how the end of the line (cap) is drawn,
|
||||
// Can be one of: NVG_BUTT (default), NVG_ROUND, NVG_SQUARE.
|
||||
void nvgLineCap(NVGcontext* ctx, int cap);
|
||||
|
||||
// Sets how sharp path corners are drawn.
|
||||
// Can be one of NVG_MITER (default), NVG_ROUND, NVG_BEVEL.
|
||||
void nvgLineJoin(NVGcontext* ctx, int join);
|
||||
|
||||
// Sets the transparency applied to all rendered shapes.
|
||||
// Already transparent paths will get proportionally more transparent as well.
|
||||
void nvgGlobalAlpha(NVGcontext* ctx, float alpha);
|
||||
|
||||
//
|
||||
// Transforms
|
||||
//
|
||||
// The paths, gradients, patterns and scissor region are transformed by an transformation
|
||||
// matrix at the time when they are passed to the API.
|
||||
// The current transformation matrix is a affine matrix:
|
||||
// [sx kx tx]
|
||||
// [ky sy ty]
|
||||
// [ 0 0 1]
|
||||
// Where: sx,sy define scaling, kx,ky skewing, and tx,ty translation.
|
||||
// The last row is assumed to be 0,0,1 and is not stored.
|
||||
//
|
||||
// Apart from nvgResetTransform(), each transformation function first creates
|
||||
// specific transformation matrix and pre-multiplies the current transformation by it.
|
||||
//
|
||||
// Current coordinate system (transformation) can be saved and restored using nvgSave() and nvgRestore().
|
||||
|
||||
// Resets current transform to a identity matrix.
|
||||
void nvgResetTransform(NVGcontext* ctx);
|
||||
|
||||
// Premultiplies current coordinate system by specified matrix.
|
||||
// The parameters are interpreted as matrix as follows:
|
||||
// [a c e]
|
||||
// [b d f]
|
||||
// [0 0 1]
|
||||
void nvgTransform(NVGcontext* ctx, float a, float b, float c, float d, float e, float f);
|
||||
|
||||
// Translates current coordinate system.
|
||||
void nvgTranslate(NVGcontext* ctx, float x, float y);
|
||||
|
||||
// Rotates current coordinate system. Angle is specified in radians.
|
||||
void nvgRotate(NVGcontext* ctx, float angle);
|
||||
|
||||
// Skews the current coordinate system along X axis. Angle is specified in radians.
|
||||
void nvgSkewX(NVGcontext* ctx, float angle);
|
||||
|
||||
// Skews the current coordinate system along Y axis. Angle is specified in radians.
|
||||
void nvgSkewY(NVGcontext* ctx, float angle);
|
||||
|
||||
// Scales the current coordinate system.
|
||||
void nvgScale(NVGcontext* ctx, float x, float y);
|
||||
|
||||
// Stores the top part (a-f) of the current transformation matrix in to the specified buffer.
|
||||
// [a c e]
|
||||
// [b d f]
|
||||
// [0 0 1]
|
||||
// There should be space for 6 floats in the return buffer for the values a-f.
|
||||
void nvgCurrentTransform(NVGcontext* ctx, float* xform);
|
||||
|
||||
|
||||
// The following functions can be used to make calculations on 2x3 transformation matrices.
|
||||
// A 2x3 matrix is represented as float[6].
|
||||
|
||||
// Sets the transform to identity matrix.
|
||||
void nvgTransformIdentity(float* dst);
|
||||
|
||||
// Sets the transform to translation matrix matrix.
|
||||
void nvgTransformTranslate(float* dst, float tx, float ty);
|
||||
|
||||
// Sets the transform to scale matrix.
|
||||
void nvgTransformScale(float* dst, float sx, float sy);
|
||||
|
||||
// Sets the transform to rotate matrix. Angle is specified in radians.
|
||||
void nvgTransformRotate(float* dst, float a);
|
||||
|
||||
// Sets the transform to skew-x matrix. Angle is specified in radians.
|
||||
void nvgTransformSkewX(float* dst, float a);
|
||||
|
||||
// Sets the transform to skew-y matrix. Angle is specified in radians.
|
||||
void nvgTransformSkewY(float* dst, float a);
|
||||
|
||||
// Sets the transform to the result of multiplication of two transforms, of A = A*B.
|
||||
void nvgTransformMultiply(float* dst, const float* src);
|
||||
|
||||
// Sets the transform to the result of multiplication of two transforms, of A = B*A.
|
||||
void nvgTransformPremultiply(float* dst, const float* src);
|
||||
|
||||
// Sets the destination to inverse of specified transform.
|
||||
// Returns 1 if the inverse could be calculated, else 0.
|
||||
int nvgTransformInverse(float* dst, const float* src);
|
||||
|
||||
// Transform a point by given transform.
|
||||
void nvgTransformPoint(float* dstx, float* dsty, const float* xform, float srcx, float srcy);
|
||||
|
||||
// Converts degrees to radians and vice versa.
|
||||
float nvgDegToRad(float deg);
|
||||
float nvgRadToDeg(float rad);
|
||||
|
||||
//
|
||||
// Images
|
||||
//
|
||||
// NanoVG allows you to load jpg, png, psd, tga, pic and gif files to be used for rendering.
|
||||
// In addition you can upload your own image. The image loading is provided by stb_image.
|
||||
// The parameter imageFlags is combination of flags defined in NVGimageFlags.
|
||||
|
||||
// Creates image by loading it from the disk from specified file name.
|
||||
// Returns handle to the image.
|
||||
int nvgCreateImage(NVGcontext* ctx, const char* filename, int imageFlags);
|
||||
|
||||
// Creates image by loading it from the specified chunk of memory.
|
||||
// Returns handle to the image.
|
||||
int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int ndata);
|
||||
|
||||
// Creates image from specified image data.
|
||||
// Returns handle to the image.
|
||||
int nvgCreateImageRGBA(NVGcontext* ctx, int w, int h, int imageFlags, const unsigned char* data);
|
||||
|
||||
// Updates image data specified by image handle.
|
||||
void nvgUpdateImage(NVGcontext* ctx, int image, const unsigned char* data);
|
||||
|
||||
// Returns the dimensions of a created image.
|
||||
void nvgImageSize(NVGcontext* ctx, int image, int* w, int* h);
|
||||
|
||||
// Deletes created image.
|
||||
void nvgDeleteImage(NVGcontext* ctx, int image);
|
||||
|
||||
//
|
||||
// Paints
|
||||
//
|
||||
// NanoVG supports four types of paints: linear gradient, box gradient, radial gradient and image pattern.
|
||||
// These can be used as paints for strokes and fills.
|
||||
|
||||
// Creates and returns a linear gradient. Parameters (sx,sy)-(ex,ey) specify the start and end coordinates
|
||||
// of the linear gradient, icol specifies the start color and ocol the end color.
|
||||
// The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint().
|
||||
NVGpaint nvgLinearGradient(NVGcontext* ctx, float sx, float sy, float ex, float ey,
|
||||
NVGcolor icol, NVGcolor ocol);
|
||||
|
||||
// Creates and returns a box gradient. Box gradient is a feathered rounded rectangle, it is useful for rendering
|
||||
// drop shadows or highlights for boxes. Parameters (x,y) define the top-left corner of the rectangle,
|
||||
// (w,h) define the size of the rectangle, r defines the corner radius, and f feather. Feather defines how blurry
|
||||
// the border of the rectangle is. Parameter icol specifies the inner color and ocol the outer color of the gradient.
|
||||
// The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint().
|
||||
NVGpaint nvgBoxGradient(NVGcontext* ctx, float x, float y, float w, float h,
|
||||
float r, float f, NVGcolor icol, NVGcolor ocol);
|
||||
|
||||
// Creates and returns a radial gradient. Parameters (cx,cy) specify the center, inr and outr specify
|
||||
// the inner and outer radius of the gradient, icol specifies the start color and ocol the end color.
|
||||
// The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint().
|
||||
NVGpaint nvgRadialGradient(NVGcontext* ctx, float cx, float cy, float inr, float outr,
|
||||
NVGcolor icol, NVGcolor ocol);
|
||||
|
||||
// Creates and returns an image patter. Parameters (ox,oy) specify the left-top location of the image pattern,
|
||||
// (ex,ey) the size of one image, angle rotation around the top-left corner, image is handle to the image to render.
|
||||
// The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint().
|
||||
NVGpaint nvgImagePattern(NVGcontext* ctx, float ox, float oy, float ex, float ey,
|
||||
float angle, int image, float alpha);
|
||||
|
||||
//
|
||||
// Scissoring
|
||||
//
|
||||
// Scissoring allows you to clip the rendering into a rectangle. This is useful for various
|
||||
// user interface cases like rendering a text edit or a timeline.
|
||||
|
||||
// Sets the current scissor rectangle.
|
||||
// The scissor rectangle is transformed by the current transform.
|
||||
void nvgScissor(NVGcontext* ctx, float x, float y, float w, float h);
|
||||
|
||||
// Intersects current scissor rectangle with the specified rectangle.
|
||||
// The scissor rectangle is transformed by the current transform.
|
||||
// Note: in case the rotation of previous scissor rect differs from
|
||||
// the current one, the intersection will be done between the specified
|
||||
// rectangle and the previous scissor rectangle transformed in the current
|
||||
// transform space. The resulting shape is always rectangle.
|
||||
void nvgIntersectScissor(NVGcontext* ctx, float x, float y, float w, float h);
|
||||
|
||||
// Reset and disables scissoring.
|
||||
void nvgResetScissor(NVGcontext* ctx);
|
||||
|
||||
//
|
||||
// Paths
|
||||
//
|
||||
// Drawing a new shape starts with nvgBeginPath(), it clears all the currently defined paths.
|
||||
// Then you define one or more paths and sub-paths which describe the shape. The are functions
|
||||
// to draw common shapes like rectangles and circles, and lower level step-by-step functions,
|
||||
// which allow to define a path curve by curve.
|
||||
//
|
||||
// NanoVG uses even-odd fill rule to draw the shapes. Solid shapes should have counter clockwise
|
||||
// winding and holes should have counter clockwise order. To specify winding of a path you can
|
||||
// call nvgPathWinding(). This is useful especially for the common shapes, which are drawn CCW.
|
||||
//
|
||||
// Finally you can fill the path using current fill style by calling nvgFill(), and stroke it
|
||||
// with current stroke style by calling nvgStroke().
|
||||
//
|
||||
// The curve segments and sub-paths are transformed by the current transform.
|
||||
|
||||
// Clears the current path and sub-paths.
|
||||
void nvgBeginPath(NVGcontext* ctx);
|
||||
|
||||
// Starts new sub-path with specified point as first point.
|
||||
void nvgMoveTo(NVGcontext* ctx, float x, float y);
|
||||
|
||||
// Adds line segment from the last point in the path to the specified point.
|
||||
void nvgLineTo(NVGcontext* ctx, float x, float y);
|
||||
|
||||
// Adds cubic bezier segment from last point in the path via two control points to the specified point.
|
||||
void nvgBezierTo(NVGcontext* ctx, float c1x, float c1y, float c2x, float c2y, float x, float y);
|
||||
|
||||
// Adds quadratic bezier segment from last point in the path via a control point to the specified point.
|
||||
void nvgQuadTo(NVGcontext* ctx, float cx, float cy, float x, float y);
|
||||
|
||||
// Adds an arc segment at the corner defined by the last path point, and two specified points.
|
||||
void nvgArcTo(NVGcontext* ctx, float x1, float y1, float x2, float y2, float radius);
|
||||
|
||||
// Closes current sub-path with a line segment.
|
||||
void nvgClosePath(NVGcontext* ctx);
|
||||
|
||||
// Sets the current sub-path winding, see NVGwinding and NVGsolidity.
|
||||
void nvgPathWinding(NVGcontext* ctx, int dir);
|
||||
|
||||
// Creates new circle arc shaped sub-path. The arc center is at cx,cy, the arc radius is r,
|
||||
// and the arc is drawn from angle a0 to a1, and swept in direction dir (NVG_CCW, or NVG_CW).
|
||||
// Angles are specified in radians.
|
||||
void nvgArc(NVGcontext* ctx, float cx, float cy, float r, float a0, float a1, int dir);
|
||||
|
||||
// Creates new rectangle shaped sub-path.
|
||||
void nvgRect(NVGcontext* ctx, float x, float y, float w, float h);
|
||||
|
||||
// Creates new rounded rectangle shaped sub-path.
|
||||
void nvgRoundedRect(NVGcontext* ctx, float x, float y, float w, float h, float r);
|
||||
|
||||
// Creates new rounded rectangle shaped sub-path with varying radii for each corner.
|
||||
void nvgRoundedRectVarying(NVGcontext* ctx, float x, float y, float w, float h, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft);
|
||||
|
||||
// Creates new ellipse shaped sub-path.
|
||||
void nvgEllipse(NVGcontext* ctx, float cx, float cy, float rx, float ry);
|
||||
|
||||
// Creates new circle shaped sub-path.
|
||||
void nvgCircle(NVGcontext* ctx, float cx, float cy, float r);
|
||||
|
||||
// Fills the current path with current fill style.
|
||||
void nvgFill(NVGcontext* ctx);
|
||||
|
||||
// Fills the current path with current stroke style.
|
||||
void nvgStroke(NVGcontext* ctx);
|
||||
|
||||
|
||||
//
|
||||
// Text
|
||||
//
|
||||
// NanoVG allows you to load .ttf files and use the font to render text.
|
||||
//
|
||||
// The appearance of the text can be defined by setting the current text style
|
||||
// and by specifying the fill color. Common text and font settings such as
|
||||
// font size, letter spacing and text align are supported. Font blur allows you
|
||||
// to create simple text effects such as drop shadows.
|
||||
//
|
||||
// At render time the font face can be set based on the font handles or name.
|
||||
//
|
||||
// Font measure functions return values in local space, the calculations are
|
||||
// carried in the same resolution as the final rendering. This is done because
|
||||
// the text glyph positions are snapped to the nearest pixels sharp rendering.
|
||||
//
|
||||
// The local space means that values are not rotated or scale as per the current
|
||||
// transformation. For example if you set font size to 12, which would mean that
|
||||
// line height is 16, then regardless of the current scaling and rotation, the
|
||||
// returned line height is always 16. Some measures may vary because of the scaling
|
||||
// since aforementioned pixel snapping.
|
||||
//
|
||||
// While this may sound a little odd, the setup allows you to always render the
|
||||
// same way regardless of scaling. I.e. following works regardless of scaling:
|
||||
//
|
||||
// const char* txt = "Text me up.";
|
||||
// nvgTextBounds(vg, x,y, txt, NULL, bounds);
|
||||
// nvgBeginPath(vg);
|
||||
// nvgRoundedRect(vg, bounds[0],bounds[1], bounds[2]-bounds[0], bounds[3]-bounds[1]);
|
||||
// nvgFill(vg);
|
||||
//
|
||||
// Note: currently only solid color fill is supported for text.
|
||||
|
||||
// Creates font by loading it from the disk from specified file name.
|
||||
// Returns handle to the font.
|
||||
int nvgCreateFont(NVGcontext* ctx, const char* name, const char* filename);
|
||||
|
||||
// Creates font by loading it from the specified memory chunk.
|
||||
// Returns handle to the font.
|
||||
int nvgCreateFontMem(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData);
|
||||
|
||||
// Finds a loaded font of specified name, and returns handle to it, or -1 if the font is not found.
|
||||
int nvgFindFont(NVGcontext* ctx, const char* name);
|
||||
|
||||
// Adds a fallback font by handle.
|
||||
int nvgAddFallbackFontId(NVGcontext* ctx, int baseFont, int fallbackFont);
|
||||
|
||||
// Adds a fallback font by name.
|
||||
int nvgAddFallbackFont(NVGcontext* ctx, const char* baseFont, const char* fallbackFont);
|
||||
|
||||
// Sets the font size of current text style.
|
||||
void nvgFontSize(NVGcontext* ctx, float size);
|
||||
|
||||
// Sets the blur of current text style.
|
||||
void nvgFontBlur(NVGcontext* ctx, float blur);
|
||||
|
||||
// Sets the letter spacing of current text style.
|
||||
void nvgTextLetterSpacing(NVGcontext* ctx, float spacing);
|
||||
|
||||
// Sets the proportional line height of current text style. The line height is specified as multiple of font size.
|
||||
void nvgTextLineHeight(NVGcontext* ctx, float lineHeight);
|
||||
|
||||
// Sets the text align of current text style, see NVGalign for options.
|
||||
void nvgTextAlign(NVGcontext* ctx, int align);
|
||||
|
||||
// Sets the font face based on specified id of current text style.
|
||||
void nvgFontFaceId(NVGcontext* ctx, int font);
|
||||
|
||||
// Sets the font face based on specified name of current text style.
|
||||
void nvgFontFace(NVGcontext* ctx, const char* font);
|
||||
|
||||
// Draws text string at specified location. If end is specified only the sub-string up to the end is drawn.
|
||||
float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char* end);
|
||||
|
||||
// Draws multi-line text string at specified location wrapped at the specified width. If end is specified only the sub-string up to the end is drawn.
|
||||
// White space is stripped at the beginning of the rows, the text is split at word boundaries or when new-line characters are encountered.
|
||||
// Words longer than the max width are slit at nearest character (i.e. no hyphenation).
|
||||
void nvgTextBox(NVGcontext* ctx, float x, float y, float breakRowWidth, const char* string, const char* end);
|
||||
|
||||
// Measures the specified text string. Parameter bounds should be a pointer to float[4],
|
||||
// if the bounding box of the text should be returned. The bounds value are [xmin,ymin, xmax,ymax]
|
||||
// Returns the horizontal advance of the measured text (i.e. where the next character should drawn).
|
||||
// Measured values are returned in local coordinate space.
|
||||
float nvgTextBounds(NVGcontext* ctx, float x, float y, const char* string, const char* end, float* bounds);
|
||||
|
||||
// Measures the specified multi-text string. Parameter bounds should be a pointer to float[4],
|
||||
// if the bounding box of the text should be returned. The bounds value are [xmin,ymin, xmax,ymax]
|
||||
// Measured values are returned in local coordinate space.
|
||||
void nvgTextBoxBounds(NVGcontext* ctx, float x, float y, float breakRowWidth, const char* string, const char* end, float* bounds);
|
||||
|
||||
// Calculates the glyph x positions of the specified text. If end is specified only the sub-string will be used.
|
||||
// Measured values are returned in local coordinate space.
|
||||
int nvgTextGlyphPositions(NVGcontext* ctx, float x, float y, const char* string, const char* end, NVGglyphPosition* positions, int maxPositions);
|
||||
|
||||
// Returns the vertical metrics based on the current text style.
|
||||
// Measured values are returned in local coordinate space.
|
||||
void nvgTextMetrics(NVGcontext* ctx, float* ascender, float* descender, float* lineh);
|
||||
|
||||
// Breaks the specified text into lines. If end is specified only the sub-string will be used.
|
||||
// White space is stripped at the beginning of the rows, the text is split at word boundaries or when new-line characters are encountered.
|
||||
// Words longer than the max width are slit at nearest character (i.e. no hyphenation).
|
||||
int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, float breakRowWidth, NVGtextRow* rows, int maxRows);
|
||||
|
||||
//
|
||||
// Internal Render API
|
||||
//
|
||||
enum NVGtexture {
|
||||
NVG_TEXTURE_ALPHA = 0x01,
|
||||
NVG_TEXTURE_RGBA = 0x02,
|
||||
};
|
||||
|
||||
struct NVGscissor {
|
||||
float xform[6];
|
||||
float extent[2];
|
||||
};
|
||||
typedef struct NVGscissor NVGscissor;
|
||||
|
||||
struct NVGvertex {
|
||||
float x,y,u,v;
|
||||
};
|
||||
typedef struct NVGvertex NVGvertex;
|
||||
|
||||
struct NVGpath {
|
||||
int first;
|
||||
int count;
|
||||
unsigned char closed;
|
||||
int nbevel;
|
||||
NVGvertex* fill;
|
||||
int nfill;
|
||||
NVGvertex* stroke;
|
||||
int nstroke;
|
||||
int winding;
|
||||
int convex;
|
||||
};
|
||||
typedef struct NVGpath NVGpath;
|
||||
|
||||
struct NVGparams {
|
||||
void* userPtr;
|
||||
int edgeAntiAlias;
|
||||
int (*renderCreate)(void* uptr);
|
||||
int (*renderCreateTexture)(void* uptr, int type, int w, int h, int imageFlags, const unsigned char* data);
|
||||
int (*renderDeleteTexture)(void* uptr, int image);
|
||||
int (*renderUpdateTexture)(void* uptr, int image, int x, int y, int w, int h, const unsigned char* data);
|
||||
int (*renderGetTextureSize)(void* uptr, int image, int* w, int* h);
|
||||
void (*renderViewport)(void* uptr, float width, float height, float devicePixelRatio);
|
||||
void (*renderCancel)(void* uptr);
|
||||
void (*renderFlush)(void* uptr);
|
||||
void (*renderFill)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, const float* bounds, const NVGpath* paths, int npaths);
|
||||
void (*renderStroke)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, float strokeWidth, const NVGpath* paths, int npaths);
|
||||
void (*renderTriangles)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, const NVGvertex* verts, int nverts);
|
||||
void (*renderDelete)(void* uptr);
|
||||
};
|
||||
typedef struct NVGparams NVGparams;
|
||||
|
||||
// Constructor and destructor, called by the render back-end.
|
||||
NVGcontext* nvgCreateInternal(NVGparams* params);
|
||||
void nvgDeleteInternal(NVGcontext* ctx);
|
||||
|
||||
NVGparams* nvgInternalParams(NVGcontext* ctx);
|
||||
|
||||
// Debug function to dump cached path data.
|
||||
void nvgDebugDumpPathCache(NVGcontext* ctx);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#define NVG_NOTUSED(v) for (;;) { (void)(1 ? (void)0 : ( (void)(v) ) ); break; }
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NANOVG_H
|
||||
1649
lib/borealis/library/include/borealis/extern/nanovg/nanovg_gl.h
vendored
Normal file
1649
lib/borealis/library/include/borealis/extern/nanovg/nanovg_gl.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
154
lib/borealis/library/include/borealis/extern/nanovg/nanovg_gl_utils.h
vendored
Normal file
154
lib/borealis/library/include/borealis/extern/nanovg/nanovg_gl_utils.h
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
//
|
||||
// Copyright (c) 2009-2013 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
#ifndef NANOVG_GL_UTILS_H
|
||||
#define NANOVG_GL_UTILS_H
|
||||
|
||||
struct NVGLUframebuffer {
|
||||
NVGcontext* ctx;
|
||||
GLuint fbo;
|
||||
GLuint rbo;
|
||||
GLuint texture;
|
||||
int image;
|
||||
};
|
||||
typedef struct NVGLUframebuffer NVGLUframebuffer;
|
||||
|
||||
// Helper function to create GL frame buffer to render to.
|
||||
void nvgluBindFramebuffer(NVGLUframebuffer* fb);
|
||||
NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h, int imageFlags);
|
||||
void nvgluDeleteFramebuffer(NVGLUframebuffer* fb);
|
||||
|
||||
#endif // NANOVG_GL_UTILS_H
|
||||
|
||||
#ifdef NANOVG_GL_IMPLEMENTATION
|
||||
|
||||
#if defined(NANOVG_GL3) || defined(NANOVG_GLES2) || defined(NANOVG_GLES3)
|
||||
// FBO is core in OpenGL 3>.
|
||||
# define NANOVG_FBO_VALID 1
|
||||
#elif defined(NANOVG_GL2)
|
||||
// On OS X including glext defines FBO on GL2 too.
|
||||
# ifdef __APPLE__
|
||||
# include <OpenGL/glext.h>
|
||||
# define NANOVG_FBO_VALID 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static GLint defaultFBO = -1;
|
||||
|
||||
NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h, int imageFlags)
|
||||
{
|
||||
#ifdef NANOVG_FBO_VALID
|
||||
GLint defaultFBO;
|
||||
GLint defaultRBO;
|
||||
NVGLUframebuffer* fb = NULL;
|
||||
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO);
|
||||
glGetIntegerv(GL_RENDERBUFFER_BINDING, &defaultRBO);
|
||||
|
||||
fb = (NVGLUframebuffer*)malloc(sizeof(NVGLUframebuffer));
|
||||
if (fb == NULL) goto error;
|
||||
memset(fb, 0, sizeof(NVGLUframebuffer));
|
||||
|
||||
fb->image = nvgCreateImageRGBA(ctx, w, h, imageFlags | NVG_IMAGE_FLIPY | NVG_IMAGE_PREMULTIPLIED, NULL);
|
||||
|
||||
#if defined NANOVG_GL2
|
||||
fb->texture = nvglImageHandleGL2(ctx, fb->image);
|
||||
#elif defined NANOVG_GL3
|
||||
fb->texture = nvglImageHandleGL3(ctx, fb->image);
|
||||
#elif defined NANOVG_GLES2
|
||||
fb->texture = nvglImageHandleGLES2(ctx, fb->image);
|
||||
#elif defined NANOVG_GLES3
|
||||
fb->texture = nvglImageHandleGLES3(ctx, fb->image);
|
||||
#endif
|
||||
|
||||
fb->ctx = ctx;
|
||||
|
||||
// frame buffer object
|
||||
glGenFramebuffers(1, &fb->fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb->fbo);
|
||||
|
||||
// render buffer object
|
||||
glGenRenderbuffers(1, &fb->rbo);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, fb->rbo);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, w, h);
|
||||
|
||||
// combine all
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb->texture, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb->rbo);
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
#ifdef GL_DEPTH24_STENCIL8
|
||||
// If GL_STENCIL_INDEX8 is not supported, try GL_DEPTH24_STENCIL8 as a fallback.
|
||||
// Some graphics cards require a depth buffer along with a stencil.
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, w, h);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb->texture, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb->rbo);
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
#endif // GL_DEPTH24_STENCIL8
|
||||
goto error;
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, defaultRBO);
|
||||
return fb;
|
||||
error:
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, defaultRBO);
|
||||
nvgluDeleteFramebuffer(fb);
|
||||
return NULL;
|
||||
#else
|
||||
NVG_NOTUSED(ctx);
|
||||
NVG_NOTUSED(w);
|
||||
NVG_NOTUSED(h);
|
||||
NVG_NOTUSED(imageFlags);
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void nvgluBindFramebuffer(NVGLUframebuffer* fb)
|
||||
{
|
||||
#ifdef NANOVG_FBO_VALID
|
||||
if (defaultFBO == -1) glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb != NULL ? fb->fbo : defaultFBO);
|
||||
#else
|
||||
NVG_NOTUSED(fb);
|
||||
#endif
|
||||
}
|
||||
|
||||
void nvgluDeleteFramebuffer(NVGLUframebuffer* fb)
|
||||
{
|
||||
#ifdef NANOVG_FBO_VALID
|
||||
if (fb == NULL) return;
|
||||
if (fb->fbo != 0)
|
||||
glDeleteFramebuffers(1, &fb->fbo);
|
||||
if (fb->rbo != 0)
|
||||
glDeleteRenderbuffers(1, &fb->rbo);
|
||||
if (fb->image >= 0)
|
||||
nvgDeleteImage(fb->ctx, fb->image);
|
||||
fb->ctx = NULL;
|
||||
fb->fbo = 0;
|
||||
fb->rbo = 0;
|
||||
fb->texture = 0;
|
||||
fb->image = -1;
|
||||
free(fb);
|
||||
#else
|
||||
NVG_NOTUSED(fb);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // NANOVG_GL_IMPLEMENTATION
|
||||
7547
lib/borealis/library/include/borealis/extern/nanovg/stb_image.h
vendored
Normal file
7547
lib/borealis/library/include/borealis/extern/nanovg/stb_image.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4883
lib/borealis/library/include/borealis/extern/nanovg/stb_truetype.h
vendored
Normal file
4883
lib/borealis/library/include/borealis/extern/nanovg/stb_truetype.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
49
lib/borealis/library/include/borealis/frame_context.hpp
Normal file
49
lib/borealis/library/include/borealis/frame_context.hpp
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nanovg.h>
|
||||
|
||||
#include <borealis/style.hpp>
|
||||
#include <borealis/theme.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
class FontStash
|
||||
{
|
||||
public:
|
||||
int regular = 0;
|
||||
int korean = 0;
|
||||
|
||||
int material = 0;
|
||||
int sharedSymbols = 0;
|
||||
};
|
||||
|
||||
class FrameContext
|
||||
{
|
||||
public:
|
||||
NVGcontext* vg = nullptr;
|
||||
float pixelRatio = 0.0;
|
||||
FontStash* fontStash = nullptr;
|
||||
ThemeValues* theme = nullptr;
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
42
lib/borealis/library/include/borealis/header.hpp
Normal file
42
lib/borealis/library/include/borealis/header.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/view.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// A simple header with text, a rectangle on the left
|
||||
// and a separator
|
||||
class Header : public View
|
||||
{
|
||||
private:
|
||||
std::string label;
|
||||
std::string sublabel;
|
||||
bool separator;
|
||||
|
||||
public:
|
||||
Header(std::string label, bool separator = true, std::string sublabel = "");
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
63
lib/borealis/library/include/borealis/hint.hpp
Normal file
63
lib/borealis/library/include/borealis/hint.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2020 WerWolv
|
||||
Copyright (C) 2020 natinusala
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/box_layout.hpp>
|
||||
#include <borealis/label.hpp>
|
||||
#include <borealis/view.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// Displays button hints for the currently focused view
|
||||
// Depending on the view's available actions
|
||||
// there can only be one Hint visible at any time
|
||||
class Hint : public BoxLayout
|
||||
{
|
||||
private:
|
||||
bool animate;
|
||||
|
||||
GenericEvent::Subscription globalFocusEventSubscriptor;
|
||||
VoidEvent::Subscription globalHintsUpdateEventSubscriptor;
|
||||
|
||||
static inline std::vector<Hint*> globalHintStack;
|
||||
|
||||
static void pushHint(Hint* hint);
|
||||
static void popHint(Hint* hint);
|
||||
static void animateHints();
|
||||
|
||||
static std::string getKeyIcon(Key key);
|
||||
|
||||
void rebuildHints();
|
||||
|
||||
public:
|
||||
Hint(bool animate = true);
|
||||
~Hint();
|
||||
|
||||
void willAppear(bool resetState = false) override;
|
||||
void willDisappear(bool resetState = false) override;
|
||||
|
||||
void setAnimate(bool animate)
|
||||
{
|
||||
this->animate = animate;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
78
lib/borealis/library/include/borealis/image.hpp
Normal file
78
lib/borealis/library/include/borealis/image.hpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 WerWolv
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/frame_context.hpp>
|
||||
#include <borealis/view.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
enum class ImageScaleType
|
||||
{
|
||||
NO_RESIZE = 0, // Nothing is resized
|
||||
FIT, // The image is shrinked to fit the view boundaries
|
||||
CROP, // The image is not resized but is cropped if bigger than the view
|
||||
SCALE, // The image is stretched to match the view boundaries
|
||||
VIEW_RESIZE // The view is resized to match the image
|
||||
};
|
||||
|
||||
// An image
|
||||
class Image : public View
|
||||
{
|
||||
public:
|
||||
Image(std::string imagePath);
|
||||
Image(unsigned char* buffer, size_t bufferSize);
|
||||
~Image();
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
|
||||
|
||||
void setImage(unsigned char* buffer, size_t bufferSize);
|
||||
void setImage(std::string imagePath);
|
||||
|
||||
void setScaleType(ImageScaleType imageScaleType);
|
||||
void setOpacity(float opacity);
|
||||
|
||||
void setCornerRadius(float radius)
|
||||
{
|
||||
this->cornerRadius = radius;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string imagePath;
|
||||
unsigned char* imageBuffer = nullptr;
|
||||
size_t imageBufferSize = 0;
|
||||
|
||||
int texture = -1;
|
||||
NVGpaint imgPaint;
|
||||
|
||||
ImageScaleType imageScaleType = ImageScaleType::FIT;
|
||||
|
||||
float cornerRadius = 0;
|
||||
|
||||
int imageX = 0, imageY = 0;
|
||||
int imageWidth = 0, imageHeight = 0;
|
||||
int origViewWidth = 0, origViewHeight = 0;
|
||||
|
||||
void reloadTexture();
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
112
lib/borealis/library/include/borealis/label.hpp
Normal file
112
lib/borealis/library/include/borealis/label.hpp
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019-2020 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/view.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
enum class LabelStyle
|
||||
{
|
||||
REGULAR = 0,
|
||||
MEDIUM,
|
||||
SMALL,
|
||||
DESCRIPTION,
|
||||
CRASH,
|
||||
BUTTON_PLAIN,
|
||||
BUTTON_PLAIN_DISABLED,
|
||||
BUTTON_BORDERLESS,
|
||||
LIST_ITEM,
|
||||
NOTIFICATION,
|
||||
DIALOG,
|
||||
BUTTON_DIALOG,
|
||||
HINT
|
||||
};
|
||||
|
||||
// A Label, multiline or with a ticker
|
||||
class Label : public View
|
||||
{
|
||||
private:
|
||||
std::string text;
|
||||
|
||||
bool multiline;
|
||||
unsigned fontSize;
|
||||
float lineHeight;
|
||||
LabelStyle labelStyle;
|
||||
|
||||
NVGalign horizontalAlign = NVG_ALIGN_LEFT;
|
||||
NVGalign verticalAlign = NVG_ALIGN_MIDDLE;
|
||||
|
||||
NVGcolor customColor;
|
||||
bool useCustomColor = false;
|
||||
|
||||
int customFont;
|
||||
bool useCustomFont = false;
|
||||
|
||||
public:
|
||||
Label(LabelStyle labelStyle, std::string text, bool multiline = false);
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
|
||||
|
||||
void setVerticalAlign(NVGalign align);
|
||||
void setHorizontalAlign(NVGalign align);
|
||||
void setText(std::string text);
|
||||
void setStyle(LabelStyle style);
|
||||
void setFontSize(unsigned size);
|
||||
|
||||
/**
|
||||
* Sets the label color
|
||||
*/
|
||||
void setColor(NVGcolor color);
|
||||
|
||||
/**
|
||||
* Unsets the label color - it
|
||||
* will now use the default one
|
||||
* for the label style
|
||||
*/
|
||||
void unsetColor();
|
||||
|
||||
/**
|
||||
* Returns the effective label color
|
||||
* = custom or the style default
|
||||
*/
|
||||
NVGcolor getColor(ThemeValues* theme);
|
||||
|
||||
/**
|
||||
* Sets the font id
|
||||
*/
|
||||
void setFont(int fontId);
|
||||
|
||||
/**
|
||||
* Unsets the font id - it
|
||||
* will now use the regular one
|
||||
*/
|
||||
void unsetFont();
|
||||
|
||||
/**
|
||||
* Returns the font used
|
||||
* = custom or the regular font
|
||||
*/
|
||||
int getFont(FontStash* stash);
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
51
lib/borealis/library/include/borealis/layer_view.hpp
Normal file
51
lib/borealis/library/include/borealis/layer_view.hpp
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 WerWolv
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/view.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// A view containing multiple children views with the ability to freely switch between these layers
|
||||
class LayerView : public View
|
||||
{
|
||||
public:
|
||||
LayerView();
|
||||
~LayerView();
|
||||
|
||||
void addLayer(View* view);
|
||||
void changeLayer(int index, bool focus = false);
|
||||
int getLayerIndex();
|
||||
|
||||
View* getDefaultFocus() override;
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
|
||||
|
||||
void willAppear(bool resetState = false) override;
|
||||
void willDisappear(bool resetState = false) override;
|
||||
|
||||
private:
|
||||
std::vector<View*> layers;
|
||||
int selectedIndex = 0;
|
||||
};
|
||||
|
||||
}
|
||||
218
lib/borealis/library/include/borealis/list.hpp
Normal file
218
lib/borealis/library/include/borealis/list.hpp
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019-2020 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/box_layout.hpp>
|
||||
#include <borealis/image.hpp>
|
||||
#include <borealis/label.hpp>
|
||||
#include <borealis/rectangle.hpp>
|
||||
#include <borealis/scroll_view.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// A list item
|
||||
// TODO: Use a Label with integrated ticker
|
||||
class ListItem : public View
|
||||
{
|
||||
private:
|
||||
std::string label;
|
||||
std::string subLabel;
|
||||
std::string value;
|
||||
bool valueFaint;
|
||||
|
||||
std::string oldValue;
|
||||
bool oldValueFaint;
|
||||
float valueAnimation = 0.0f;
|
||||
|
||||
bool checked = false; // check mark on the right
|
||||
|
||||
unsigned textSize;
|
||||
|
||||
bool drawTopSeparator = true;
|
||||
|
||||
Label* descriptionView = nullptr;
|
||||
Image* thumbnailView = nullptr;
|
||||
|
||||
bool reduceDescriptionSpacing = false;
|
||||
|
||||
GenericEvent clickEvent;
|
||||
|
||||
bool indented = false;
|
||||
|
||||
void resetValueAnimation();
|
||||
|
||||
public:
|
||||
ListItem(std::string label, std::string description = "", std::string subLabel = "");
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
|
||||
void getHighlightInsets(unsigned* top, unsigned* right, unsigned* bottom, unsigned* left) override;
|
||||
virtual bool onClick();
|
||||
View* getDefaultFocus() override;
|
||||
|
||||
void setThumbnail(Image* image);
|
||||
void setThumbnail(std::string imagePath);
|
||||
void setThumbnail(unsigned char* buffer, size_t bufferSize);
|
||||
|
||||
bool hasDescription();
|
||||
void setDrawTopSeparator(bool draw);
|
||||
|
||||
bool getReduceDescriptionSpacing();
|
||||
void setReduceDescriptionSpacing(bool value);
|
||||
|
||||
void setIndented(bool indented);
|
||||
|
||||
void setTextSize(unsigned textSize);
|
||||
|
||||
void setChecked(bool checked);
|
||||
|
||||
std::string getLabel();
|
||||
|
||||
/**
|
||||
* Sets the value of this list item
|
||||
* (the text on the right)
|
||||
* Set faint to true to have the new value
|
||||
* use a darker color (typically "OFF" labels)
|
||||
*/
|
||||
void setValue(std::string value, bool faint = false, bool animate = true);
|
||||
std::string getValue();
|
||||
|
||||
GenericEvent* getClickEvent();
|
||||
|
||||
~ListItem();
|
||||
};
|
||||
|
||||
// Some spacing (to make groups of ListItems)
|
||||
class ListItemGroupSpacing : public Rectangle
|
||||
{
|
||||
public:
|
||||
ListItemGroupSpacing(bool separator = false);
|
||||
};
|
||||
|
||||
// A list item with mutliple choices for its value
|
||||
// (will open a Dropdown)
|
||||
|
||||
// Fired when the user has selected a value
|
||||
//
|
||||
// Parameter is either the selected value index
|
||||
// or -1 if the user cancelled
|
||||
typedef Event<int> ValueSelectedEvent;
|
||||
|
||||
class SelectListItem : public ListItem
|
||||
{
|
||||
public:
|
||||
SelectListItem(std::string label, std::vector<std::string> values, unsigned selectedValue = 0);
|
||||
|
||||
void setSelectedValue(unsigned value);
|
||||
|
||||
ValueSelectedEvent* getValueSelectedEvent();
|
||||
|
||||
private:
|
||||
std::vector<std::string> values;
|
||||
unsigned selectedValue;
|
||||
|
||||
ValueSelectedEvent valueEvent;
|
||||
};
|
||||
|
||||
// A list item with a ON/OFF value
|
||||
// that can be toggled
|
||||
// Use the click event to detect when the value
|
||||
// changes
|
||||
class ToggleListItem : public ListItem
|
||||
{
|
||||
private:
|
||||
bool toggleState;
|
||||
std::string onValue, offValue;
|
||||
|
||||
void updateValue();
|
||||
|
||||
public:
|
||||
ToggleListItem(std::string label, bool initialValue, std::string description = "", std::string onValue = "On", std::string offValue = "Off");
|
||||
|
||||
virtual bool onClick() override;
|
||||
|
||||
bool getToggleState();
|
||||
};
|
||||
|
||||
// A list item which spawns the swkbd
|
||||
// to input its value (string)
|
||||
class InputListItem : public ListItem
|
||||
{
|
||||
protected:
|
||||
std::string helpText;
|
||||
int maxInputLength;
|
||||
|
||||
public:
|
||||
InputListItem(std::string label, std::string initialValue, std::string helpText, std::string description = "", int maxInputLength = 32);
|
||||
|
||||
virtual bool onClick() override;
|
||||
};
|
||||
|
||||
// A list item which spawns the swkbd
|
||||
// to input its value (integer)
|
||||
class IntegerInputListItem : public InputListItem
|
||||
{
|
||||
public:
|
||||
IntegerInputListItem(std::string label, int initialValue, std::string helpText, std::string description = "", int maxInputLength = 32);
|
||||
|
||||
virtual bool onClick() override;
|
||||
};
|
||||
|
||||
class List; // forward declaration for ListContentView::list
|
||||
|
||||
// The content view of lists (used internally)
|
||||
class ListContentView : public BoxLayout
|
||||
{
|
||||
public:
|
||||
ListContentView(List* list, size_t defaultFocus = 0);
|
||||
|
||||
protected:
|
||||
void customSpacing(View* current, View* next, int* spacing) override;
|
||||
|
||||
private:
|
||||
List* list;
|
||||
};
|
||||
|
||||
// A vertical list of various widgets, with proper margins and spacing
|
||||
// and a scroll bar
|
||||
// In practice it's a ScrollView which content view is
|
||||
// a ListContentView (BoxLayout)
|
||||
class List : public ScrollView
|
||||
{
|
||||
private:
|
||||
ListContentView* layout;
|
||||
|
||||
public:
|
||||
List(size_t defaultFocus = 0);
|
||||
~List();
|
||||
|
||||
// Wrapped BoxLayout methods
|
||||
void addView(View* view, bool fill = false);
|
||||
void clear(bool free = true);
|
||||
void setMargins(unsigned top, unsigned right, unsigned bottom, unsigned left);
|
||||
void setMarginBottom(unsigned bottom);
|
||||
void setSpacing(unsigned spacing);
|
||||
unsigned getSpacing();
|
||||
virtual void customSpacing(View* current, View* next, int* spacing);
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
49
lib/borealis/library/include/borealis/logger.hpp
Normal file
49
lib/borealis/library/include/borealis/logger.hpp
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
enum class LogLevel
|
||||
{
|
||||
ERROR = 0,
|
||||
INFO,
|
||||
DEBUG
|
||||
};
|
||||
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
static void setLogLevel(LogLevel logLevel);
|
||||
|
||||
static void error(const char* format, ...);
|
||||
static void info(const char* format, ...);
|
||||
static void debug(const char* format, ...);
|
||||
|
||||
protected:
|
||||
static void log(LogLevel logLevel, const char* prefix, const char* color, const char* format, va_list ap);
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
40
lib/borealis/library/include/borealis/material_icon.hpp
Normal file
40
lib/borealis/library/include/borealis/material_icon.hpp
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/view.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// A Material icon (from the Material font)
|
||||
class MaterialIcon : public View
|
||||
{
|
||||
private:
|
||||
std::string icon;
|
||||
unsigned middleX, middleY;
|
||||
|
||||
public:
|
||||
MaterialIcon(std::string icon);
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/animations.hpp>
|
||||
#include <borealis/label.hpp>
|
||||
#include <borealis/view.hpp>
|
||||
|
||||
#define BRLS_NOTIFICATIONS_MAX 8
|
||||
|
||||
// TODO: check in HOS that the animation duration + notification timeout are correct
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
class Notification : public View
|
||||
{
|
||||
public:
|
||||
Notification(std::string text);
|
||||
~Notification();
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
|
||||
|
||||
menu_timer_t timeoutTimer;
|
||||
|
||||
private:
|
||||
Label* label;
|
||||
};
|
||||
|
||||
class NotificationManager : public View
|
||||
{
|
||||
private:
|
||||
Notification* notifications[BRLS_NOTIFICATIONS_MAX];
|
||||
|
||||
void layoutNotification(size_t i);
|
||||
|
||||
public:
|
||||
NotificationManager();
|
||||
~NotificationManager();
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
|
||||
|
||||
void notify(std::string text);
|
||||
};
|
||||
|
||||
}; // namespace brls
|
||||
63
lib/borealis/library/include/borealis/popup_frame.hpp
Normal file
63
lib/borealis/library/include/borealis/popup_frame.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 WerWolv
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/applet_frame.hpp>
|
||||
#include <borealis/list.hpp>
|
||||
#include <borealis/view.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
class PopupFrame : public View
|
||||
{
|
||||
private:
|
||||
PopupFrame(std::string title, unsigned char* imageBuffer, size_t imageBufferSize, AppletFrame* contentView, std::string subTitleLeft = "", std::string subTitleRight = "");
|
||||
PopupFrame(std::string title, std::string imagePath, AppletFrame* contentView, std::string subTitleLeft = "", std::string subTitleRight = "");
|
||||
PopupFrame(std::string title, AppletFrame* contentView, std::string subTitleLeft = "", std::string subTitleRight = "");
|
||||
|
||||
AppletFrame* contentView = nullptr;
|
||||
|
||||
protected:
|
||||
unsigned getShowAnimationDuration(ViewAnimation animation) override;
|
||||
|
||||
public:
|
||||
~PopupFrame();
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
|
||||
View* getDefaultFocus() override;
|
||||
virtual bool onCancel();
|
||||
void willAppear(bool resetState = false) override;
|
||||
void willDisappear(bool resetState = false) override;
|
||||
|
||||
static void open(std::string title, unsigned char* imageBuffer, size_t imageBufferSize, AppletFrame* contentView, std::string subTitleLeft = "", std::string subTitleRight = "");
|
||||
static void open(std::string title, std::string imagePath, AppletFrame* contentView, std::string subTitleLeft = "", std::string subTitleRight = "");
|
||||
static void open(std::string title, AppletFrame* contentView, std::string subTitleLeft = "", std::string subTitleRight = "");
|
||||
|
||||
bool isTranslucent() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
58
lib/borealis/library/include/borealis/progress_display.hpp
Normal file
58
lib/borealis/library/include/borealis/progress_display.hpp
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 Billy Laws
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/label.hpp>
|
||||
#include <borealis/progress_spinner.hpp>
|
||||
#include <borealis/view.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// TODO: Add the "ProgressDisplayFlags_" prefix to the members
|
||||
enum ProgressDisplayFlags
|
||||
{
|
||||
SPINNER = 1u << 0,
|
||||
PERCENTAGE = 1u << 1
|
||||
};
|
||||
|
||||
inline constexpr ProgressDisplayFlags DEFAULT_PROGRESS_DISPLAY_FLAGS = (ProgressDisplayFlags)(ProgressDisplayFlags::SPINNER | ProgressDisplayFlags::PERCENTAGE);
|
||||
|
||||
// A progress bar with an optional spinner and percentage text.
|
||||
class ProgressDisplay : public View
|
||||
{
|
||||
public:
|
||||
ProgressDisplay(ProgressDisplayFlags progressFlags = DEFAULT_PROGRESS_DISPLAY_FLAGS);
|
||||
~ProgressDisplay();
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
|
||||
void willAppear(bool resetState = false) override;
|
||||
void willDisappear(bool resetState = false) override;
|
||||
|
||||
void setProgress(int current, int max);
|
||||
|
||||
private:
|
||||
float progressPercentage = 0.0f;
|
||||
Label* label;
|
||||
ProgressSpinner* spinner;
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
44
lib/borealis/library/include/borealis/progress_spinner.hpp
Normal file
44
lib/borealis/library/include/borealis/progress_spinner.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 Billy Laws
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/view.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// A progress spinner
|
||||
class ProgressSpinner : public View
|
||||
{
|
||||
public:
|
||||
ProgressSpinner();
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
|
||||
void willAppear(bool resetState = false) override;
|
||||
void willDisappear(bool resetState = false) override;
|
||||
|
||||
private:
|
||||
float animationValue = 0.0f;
|
||||
|
||||
void restartAnimation();
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
47
lib/borealis/library/include/borealis/rectangle.hpp
Normal file
47
lib/borealis/library/include/borealis/rectangle.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/frame_context.hpp>
|
||||
#include <borealis/view.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// A solid color rectangle
|
||||
class Rectangle : public View
|
||||
{
|
||||
protected:
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
|
||||
|
||||
public:
|
||||
Rectangle(NVGcolor color);
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
|
||||
void setColor(NVGcolor color);
|
||||
|
||||
~Rectangle() {}
|
||||
|
||||
private:
|
||||
NVGcolor color = nvgRGB(0, 0, 255);
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
87
lib/borealis/library/include/borealis/repeating_task.hpp
Normal file
87
lib/borealis/library/include/borealis/repeating_task.hpp
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <features/features_cpu.h>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// A task that is repeated at a given interval
|
||||
// by the UI thread
|
||||
class RepeatingTask
|
||||
{
|
||||
private:
|
||||
retro_time_t interval;
|
||||
|
||||
retro_time_t lastRun = 0;
|
||||
|
||||
bool running = false;
|
||||
bool stopRequested = false;
|
||||
|
||||
public:
|
||||
RepeatingTask(retro_time_t interval);
|
||||
virtual ~RepeatingTask();
|
||||
|
||||
/**
|
||||
* Actual code to run by the task
|
||||
* Must call RepeatingTask::run() !
|
||||
*/
|
||||
virtual void run(retro_time_t currentTime);
|
||||
|
||||
/**
|
||||
* Fired when the task starts
|
||||
*/
|
||||
virtual void onStart() {};
|
||||
|
||||
/**
|
||||
* Fired when the task stops
|
||||
*/
|
||||
virtual void onStop() {};
|
||||
|
||||
/**
|
||||
* Starts the task
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Fires the task immediately and delays the
|
||||
* next run
|
||||
*/
|
||||
void fireNow();
|
||||
|
||||
/**
|
||||
* Pauses the task without deleting it
|
||||
*/
|
||||
void pause();
|
||||
|
||||
/**
|
||||
* Stops and deletes the task
|
||||
*/
|
||||
void stop();
|
||||
|
||||
retro_time_t getInterval();
|
||||
retro_time_t getLastRun();
|
||||
|
||||
bool isRunning();
|
||||
bool isStopRequested();
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
65
lib/borealis/library/include/borealis/scroll_view.hpp
Normal file
65
lib/borealis/library/include/borealis/scroll_view.hpp
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2020 natinusala
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <borealis/view.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// TODO: horizontal scrolling, either in ScrollView or in a separate class (like Android has)
|
||||
|
||||
// A view that automatically scrolls vertically
|
||||
// when one of its children gains focus
|
||||
class ScrollView : public View
|
||||
{
|
||||
private:
|
||||
View* contentView = nullptr;
|
||||
|
||||
bool ready = false; // has layout been called at least once?
|
||||
|
||||
unsigned middleY = 0; // y + height/2
|
||||
unsigned bottomY = 0; // y + height
|
||||
|
||||
float scrollY = 0.0f; // from 0.0f to 1.0f, in % of content view height
|
||||
|
||||
bool updateScrollingOnNextLayout = false;
|
||||
bool updateScrollingOnNextFrame = false;
|
||||
|
||||
unsigned getYCenter(View* view);
|
||||
|
||||
void prebakeScrolling();
|
||||
bool updateScrolling(bool animated);
|
||||
void startScrolling(bool animated, float newScroll);
|
||||
void scrollAnimationTick();
|
||||
|
||||
public:
|
||||
~ScrollView();
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
|
||||
void willAppear(bool resetState = false) override;
|
||||
void willDisappear(bool resetState = false) override;
|
||||
View* getDefaultFocus() override;
|
||||
void onChildFocusGained(View* child) override;
|
||||
void onWindowSizeChanged() override;
|
||||
|
||||
void setContentView(View* view);
|
||||
View* getContentView();
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
94
lib/borealis/library/include/borealis/sidebar.hpp
Normal file
94
lib/borealis/library/include/borealis/sidebar.hpp
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/box_layout.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// A sidebar with multiple tabs
|
||||
class SidebarSeparator : public View
|
||||
{
|
||||
public:
|
||||
SidebarSeparator();
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
};
|
||||
|
||||
class Sidebar;
|
||||
|
||||
// TODO: Use a Label view with integrated ticker for label and sublabel
|
||||
// TODO: Have the label always tick when active
|
||||
class SidebarItem : public View
|
||||
{
|
||||
private:
|
||||
std::string label;
|
||||
bool active = false;
|
||||
|
||||
Sidebar* sidebar = nullptr;
|
||||
View* associatedView = nullptr;
|
||||
|
||||
public:
|
||||
SidebarItem(std::string label, Sidebar* sidebar);
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
|
||||
View* getDefaultFocus() override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
virtual bool onClick();
|
||||
|
||||
void setActive(bool active);
|
||||
bool isActive();
|
||||
|
||||
void onFocusGained() override;
|
||||
|
||||
void setAssociatedView(View* view);
|
||||
View* getAssociatedView();
|
||||
|
||||
~SidebarItem();
|
||||
};
|
||||
|
||||
// TODO: Add a style with icons, make it collapsible?
|
||||
class Sidebar : public BoxLayout
|
||||
{
|
||||
private:
|
||||
SidebarItem* currentActive = nullptr;
|
||||
|
||||
public:
|
||||
Sidebar();
|
||||
|
||||
SidebarItem* addItem(std::string label, View* view);
|
||||
void addSeparator();
|
||||
|
||||
void setActive(SidebarItem* item);
|
||||
|
||||
View* getDefaultFocus() override;
|
||||
void onChildFocusGained(View* child) override;
|
||||
|
||||
size_t lastFocus = 0;
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 Billy Laws
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/applet_frame.hpp>
|
||||
#include <borealis/sidebar.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// An applet frame for implementing a stage based app with a progress display in top right
|
||||
class StagedAppletFrame : public AppletFrame
|
||||
{
|
||||
public:
|
||||
StagedAppletFrame();
|
||||
~StagedAppletFrame();
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
|
||||
void addStage(View* view);
|
||||
void nextStage();
|
||||
void previousStage();
|
||||
|
||||
unsigned getCurrentStage();
|
||||
unsigned getStagesCount();
|
||||
unsigned isLastStage();
|
||||
|
||||
private:
|
||||
size_t currentStage = 0;
|
||||
std::vector<View*> stageViews;
|
||||
|
||||
void enterStage(int index, bool requestFocus);
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
323
lib/borealis/library/include/borealis/style.hpp
Normal file
323
lib/borealis/library/include/borealis/style.hpp
Normal file
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 WerWolv
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
class Style
|
||||
{
|
||||
public:
|
||||
// AppletFrame
|
||||
struct
|
||||
{
|
||||
unsigned headerHeightRegular;
|
||||
unsigned headerHeightPopup; // PopupFrame
|
||||
unsigned footerHeight;
|
||||
|
||||
unsigned imageLeftPadding;
|
||||
unsigned imageTopPadding;
|
||||
unsigned imageSize;
|
||||
unsigned separatorSpacing;
|
||||
|
||||
unsigned titleSize;
|
||||
unsigned titleStart;
|
||||
unsigned titleOffset;
|
||||
|
||||
unsigned footerTextSize;
|
||||
unsigned footerTextSpacing;
|
||||
|
||||
unsigned slideAnimation;
|
||||
} AppletFrame;
|
||||
|
||||
// Highlight
|
||||
struct
|
||||
{
|
||||
unsigned strokeWidth;
|
||||
float cornerRadius;
|
||||
|
||||
unsigned shadowWidth;
|
||||
unsigned shadowOffset;
|
||||
unsigned shadowFeather;
|
||||
unsigned shadowOpacity;
|
||||
|
||||
unsigned animationDuration;
|
||||
} Highlight;
|
||||
|
||||
// Background
|
||||
struct
|
||||
{
|
||||
unsigned sidebarBorderHeight;
|
||||
} Background;
|
||||
|
||||
// Sidebar
|
||||
struct
|
||||
{
|
||||
unsigned width;
|
||||
unsigned spacing;
|
||||
|
||||
unsigned marginLeft;
|
||||
unsigned marginRight;
|
||||
unsigned marginTop;
|
||||
unsigned marginBottom;
|
||||
|
||||
struct
|
||||
{
|
||||
unsigned height;
|
||||
unsigned textSize;
|
||||
unsigned padding;
|
||||
|
||||
unsigned textOffsetX;
|
||||
unsigned activeMarkerWidth;
|
||||
|
||||
unsigned highlight;
|
||||
} Item;
|
||||
|
||||
struct
|
||||
{
|
||||
unsigned height;
|
||||
} Separator;
|
||||
} Sidebar;
|
||||
|
||||
// List
|
||||
struct
|
||||
{
|
||||
unsigned marginLeftRight;
|
||||
unsigned marginTopBottom;
|
||||
unsigned spacing;
|
||||
|
||||
// Item
|
||||
struct
|
||||
{
|
||||
unsigned height;
|
||||
unsigned heightWithSubLabel;
|
||||
unsigned valueSize;
|
||||
unsigned padding;
|
||||
unsigned thumbnailPadding;
|
||||
|
||||
unsigned descriptionIndent;
|
||||
unsigned descriptionSpacing;
|
||||
|
||||
unsigned indent;
|
||||
|
||||
unsigned selectRadius;
|
||||
} Item;
|
||||
} List;
|
||||
|
||||
// Label
|
||||
struct
|
||||
{
|
||||
unsigned regularFontSize;
|
||||
unsigned mediumFontSize;
|
||||
unsigned smallFontSize;
|
||||
unsigned descriptionFontSize;
|
||||
unsigned crashFontSize;
|
||||
unsigned buttonFontSize;
|
||||
unsigned listItemFontSize;
|
||||
unsigned notificationFontSize;
|
||||
unsigned dialogFontSize;
|
||||
unsigned hintFontSize;
|
||||
|
||||
float lineHeight;
|
||||
float notificationLineHeight;
|
||||
} Label;
|
||||
|
||||
// CrashFrame
|
||||
struct
|
||||
{
|
||||
float labelWidth; // proportional to frame width, from 0 to 1
|
||||
unsigned boxStrokeWidth;
|
||||
unsigned boxSize;
|
||||
unsigned boxSpacing;
|
||||
unsigned buttonWidth;
|
||||
unsigned buttonHeight;
|
||||
unsigned buttonSpacing;
|
||||
} CrashFrame;
|
||||
|
||||
// Button
|
||||
struct
|
||||
{
|
||||
float cornerRadius;
|
||||
|
||||
unsigned highlightInset;
|
||||
|
||||
float shadowWidth;
|
||||
float shadowFeather;
|
||||
float shadowOpacity;
|
||||
float shadowOffset;
|
||||
} Button;
|
||||
|
||||
// TableRow
|
||||
struct
|
||||
{
|
||||
unsigned headerHeight;
|
||||
unsigned headerTextSize;
|
||||
|
||||
unsigned bodyHeight;
|
||||
unsigned bodyIndent;
|
||||
unsigned bodyTextSize;
|
||||
|
||||
unsigned padding;
|
||||
} TableRow;
|
||||
|
||||
// Dropdown
|
||||
struct
|
||||
{
|
||||
unsigned listWidth;
|
||||
unsigned listPadding;
|
||||
|
||||
unsigned listItemHeight;
|
||||
unsigned listItemTextSize;
|
||||
|
||||
unsigned headerHeight;
|
||||
unsigned headerFontSize;
|
||||
unsigned headerPadding;
|
||||
} Dropdown;
|
||||
|
||||
struct
|
||||
{
|
||||
unsigned edgePadding;
|
||||
unsigned separatorSpacing;
|
||||
unsigned footerHeight;
|
||||
unsigned imageLeftPadding;
|
||||
unsigned imageTopPadding;
|
||||
unsigned imageSize;
|
||||
unsigned contentWidth;
|
||||
unsigned contentHeight;
|
||||
|
||||
unsigned headerTextLeftPadding;
|
||||
unsigned headerTextTopPadding;
|
||||
|
||||
unsigned subTitleLeftPadding;
|
||||
unsigned subTitleTopPadding;
|
||||
unsigned subTitleSpacing;
|
||||
|
||||
unsigned subTitleSeparatorLeftPadding;
|
||||
unsigned subTitleSeparatorTopPadding;
|
||||
unsigned subTitleSeparatorHeight;
|
||||
|
||||
unsigned headerFontSize;
|
||||
unsigned subTitleFontSize;
|
||||
} PopupFrame;
|
||||
|
||||
// StagedAppletFrame
|
||||
struct
|
||||
{
|
||||
unsigned progressIndicatorSpacing;
|
||||
unsigned progressIndicatorRadiusUnselected;
|
||||
unsigned progressIndicatorRadiusSelected;
|
||||
unsigned progressIndicatorBorderWidth;
|
||||
} StagedAppletFrame;
|
||||
|
||||
// ProgressSpinner
|
||||
struct
|
||||
{
|
||||
float centerGapMultiplier;
|
||||
float barWidthMultiplier;
|
||||
unsigned animationDuration;
|
||||
} ProgressSpinner;
|
||||
|
||||
// ProgressDisplay
|
||||
struct
|
||||
{
|
||||
unsigned percentageLabelWidth;
|
||||
} ProgressDisplay;
|
||||
|
||||
// Header
|
||||
struct
|
||||
{
|
||||
unsigned height;
|
||||
unsigned padding;
|
||||
|
||||
unsigned rectangleWidth;
|
||||
|
||||
unsigned fontSize;
|
||||
} Header;
|
||||
|
||||
// FramerateCounter
|
||||
struct
|
||||
{
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
} FramerateCounter;
|
||||
|
||||
// ThumbnailSidebar
|
||||
struct
|
||||
{
|
||||
unsigned marginLeftRight;
|
||||
unsigned marginTopBottom;
|
||||
|
||||
unsigned buttonHeight;
|
||||
unsigned buttonMargin;
|
||||
} ThumbnailSidebar;
|
||||
|
||||
// AnimationDuration
|
||||
struct
|
||||
{
|
||||
unsigned show;
|
||||
unsigned showSlide;
|
||||
|
||||
unsigned highlight;
|
||||
unsigned shake;
|
||||
|
||||
unsigned collapse;
|
||||
|
||||
unsigned progress;
|
||||
|
||||
unsigned notificationTimeout;
|
||||
} AnimationDuration;
|
||||
|
||||
// Notification
|
||||
struct
|
||||
{
|
||||
unsigned width;
|
||||
unsigned padding;
|
||||
|
||||
unsigned slideAnimation;
|
||||
} Notification;
|
||||
|
||||
// Dialog
|
||||
struct
|
||||
{
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
|
||||
unsigned paddingTopBottom;
|
||||
unsigned paddingLeftRight;
|
||||
|
||||
float cornerRadius;
|
||||
|
||||
unsigned buttonHeight;
|
||||
unsigned buttonSeparatorHeight;
|
||||
|
||||
float shadowWidth;
|
||||
float shadowFeather;
|
||||
float shadowOpacity;
|
||||
float shadowOffset;
|
||||
} Dialog;
|
||||
|
||||
// As close to HOS as possible
|
||||
static Style horizon();
|
||||
|
||||
// TODO: Make a condensed style
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
35
lib/borealis/library/include/borealis/swkbd.hpp
Normal file
35
lib/borealis/library/include/borealis/swkbd.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 WerWolv
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
class Swkbd
|
||||
{
|
||||
public:
|
||||
static bool openForText(std::function<void(std::string)> f, std::string headerText = "", std::string subText = "", int maxStringLength = 32, std::string initialText = "");
|
||||
static bool openForNumber(std::function<void(int)> f, std::string headerText = "", std::string subText = "", int maxStringLength = 32, std::string initialText = "", std::string leftButton = "", std::string rightButton = "");
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
59
lib/borealis/library/include/borealis/tab_frame.hpp
Normal file
59
lib/borealis/library/include/borealis/tab_frame.hpp
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019-2020 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/applet_frame.hpp>
|
||||
#include <borealis/sidebar.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// An applet frame containing a sidebar on the left with multiple tabs
|
||||
class TabFrame : public AppletFrame
|
||||
{
|
||||
public:
|
||||
TabFrame();
|
||||
|
||||
/**
|
||||
* Adds a tab with given label and view
|
||||
* All tabs and separators must be added
|
||||
* before the TabFrame is itself added to
|
||||
* the view hierarchy
|
||||
*/
|
||||
void addTab(std::string label, View* view);
|
||||
void addSeparator();
|
||||
|
||||
View* getDefaultFocus() override;
|
||||
|
||||
virtual bool onCancel() override;
|
||||
|
||||
~TabFrame();
|
||||
|
||||
private:
|
||||
Sidebar* sidebar;
|
||||
BoxLayout* layout;
|
||||
View* rightPane = nullptr;
|
||||
|
||||
void switchToView(View* view);
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
73
lib/borealis/library/include/borealis/table.hpp
Normal file
73
lib/borealis/library/include/borealis/table.hpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/view.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// The type of a Table Row
|
||||
enum class TableRowType
|
||||
{
|
||||
HEADER = 0,
|
||||
BODY
|
||||
};
|
||||
|
||||
// A Table row
|
||||
class TableRow
|
||||
{
|
||||
private:
|
||||
TableRowType type;
|
||||
|
||||
std::string label;
|
||||
std::string value;
|
||||
|
||||
public:
|
||||
TableRow(TableRowType type, std::string label, std::string value = "");
|
||||
|
||||
std::string* getLabel();
|
||||
std::string* getValue();
|
||||
TableRowType getType();
|
||||
|
||||
void setValue(std::string value);
|
||||
};
|
||||
|
||||
// A simple, static two-columns table, as seen in
|
||||
// the Settings app (Internet connection details)
|
||||
// All rows must be added before adding the view
|
||||
// to a layout (it's static)
|
||||
class Table : public View
|
||||
{
|
||||
private:
|
||||
std::vector<TableRow*> rows;
|
||||
|
||||
public:
|
||||
~Table();
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
|
||||
|
||||
TableRow* addRow(TableRowType type, std::string label, std::string value = "");
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
43
lib/borealis/library/include/borealis/task_manager.hpp
Normal file
43
lib/borealis/library/include/borealis/task_manager.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/repeating_task.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
class TaskManager
|
||||
{
|
||||
private:
|
||||
std::vector<RepeatingTask*> repeatingTasks;
|
||||
|
||||
void stopRepeatingTask(RepeatingTask* task);
|
||||
|
||||
public:
|
||||
void frame();
|
||||
|
||||
void registerRepeatingTask(RepeatingTask* task);
|
||||
|
||||
~TaskManager();
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
96
lib/borealis/library/include/borealis/theme.hpp
Normal file
96
lib/borealis/library/include/borealis/theme.hpp
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nanovg.h>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// Theme variants
|
||||
// (used in Application)
|
||||
//
|
||||
// Not an enum class because it's used
|
||||
// as an array index in Theme
|
||||
enum ThemeVariant
|
||||
{
|
||||
ThemeVariant_LIGHT = 0,
|
||||
ThemeVariant_DARK,
|
||||
ThemeVariant_NUMBER_OF_VARIANTS
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float backgroundColor[3]; // gl color
|
||||
NVGcolor backgroundColorRGB;
|
||||
|
||||
NVGcolor textColor;
|
||||
NVGcolor descriptionColor;
|
||||
|
||||
NVGcolor notificationTextColor;
|
||||
NVGcolor backdropColor;
|
||||
|
||||
NVGcolor separatorColor;
|
||||
|
||||
NVGcolor sidebarColor;
|
||||
NVGcolor activeTabColor;
|
||||
NVGcolor sidebarSeparatorColor;
|
||||
|
||||
NVGcolor highlightBackgroundColor;
|
||||
NVGcolor highlightColor1;
|
||||
NVGcolor highlightColor2;
|
||||
|
||||
NVGcolor listItemSeparatorColor;
|
||||
NVGcolor listItemValueColor;
|
||||
NVGcolor listItemFaintValueColor;
|
||||
|
||||
NVGcolor tableEvenBackgroundColor;
|
||||
NVGcolor tableBodyTextColor;
|
||||
|
||||
NVGcolor dropdownBackgroundColor;
|
||||
|
||||
NVGcolor nextStageBulletColor;
|
||||
|
||||
NVGcolor spinnerBarColor;
|
||||
|
||||
NVGcolor headerRectangleColor;
|
||||
|
||||
NVGcolor buttonPlainEnabledBackgroundColor;
|
||||
NVGcolor buttonPlainDisabledBackgroundColor;
|
||||
NVGcolor buttonPlainEnabledTextColor;
|
||||
NVGcolor buttonPlainDisabledTextColor;
|
||||
|
||||
NVGcolor dialogColor;
|
||||
NVGcolor dialogBackdrop;
|
||||
NVGcolor dialogButtonColor;
|
||||
NVGcolor dialogButtonSeparatorColor;
|
||||
} ThemeValues;
|
||||
|
||||
// A theme contains colors for all variants
|
||||
class Theme
|
||||
{
|
||||
public:
|
||||
ThemeValues colors[ThemeVariant_NUMBER_OF_VARIANTS];
|
||||
|
||||
// As close to HOS as possible
|
||||
static Theme horizon();
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
78
lib/borealis/library/include/borealis/thumbnail_frame.hpp
Normal file
78
lib/borealis/library/include/borealis/thumbnail_frame.hpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/applet_frame.hpp>
|
||||
#include <borealis/box_layout.hpp>
|
||||
#include <borealis/button.hpp>
|
||||
#include <borealis/image.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// The sidebar used in ThumbnailFrame
|
||||
class ThumbnailSidebar : public View
|
||||
{
|
||||
private:
|
||||
Image* image = nullptr;
|
||||
Button* button = nullptr;
|
||||
|
||||
Label* title = nullptr;
|
||||
Label* subTitle = nullptr;
|
||||
|
||||
public:
|
||||
ThumbnailSidebar();
|
||||
~ThumbnailSidebar();
|
||||
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
|
||||
View* getDefaultFocus() override;
|
||||
|
||||
void setThumbnail(std::string imagePath);
|
||||
void setThumbnail(unsigned char* buffer, size_t bufferSize);
|
||||
|
||||
void setTitle(std::string title);
|
||||
void setSubtitle(std::string subTitle);
|
||||
|
||||
Button* getButton();
|
||||
};
|
||||
|
||||
// An applet frame with a sidebar on the right, containing a thumbnail
|
||||
// and a button (similar to the Wi-Fi settings in HOS)
|
||||
class ThumbnailFrame : public AppletFrame
|
||||
{
|
||||
private:
|
||||
ThumbnailSidebar* sidebar = nullptr;
|
||||
BoxLayout* boxLayout = nullptr;
|
||||
|
||||
View* thumbnailContentView = nullptr;
|
||||
|
||||
public:
|
||||
ThumbnailFrame();
|
||||
~ThumbnailFrame();
|
||||
|
||||
void setContentView(View* view) override;
|
||||
|
||||
protected:
|
||||
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
|
||||
|
||||
ThumbnailSidebar* getSidebar();
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
406
lib/borealis/library/include/borealis/view.hpp
Normal file
406
lib/borealis/library/include/borealis/view.hpp
Normal file
@@ -0,0 +1,406 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019-2020 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <features/features_cpu.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <borealis/actions.hpp>
|
||||
#include <borealis/event.hpp>
|
||||
#include <borealis/frame_context.hpp>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// The animation to play when
|
||||
// pushing or popping a view
|
||||
// (implemented in Application)
|
||||
enum class ViewAnimation
|
||||
{
|
||||
FADE, // the old view fades away and the new one fades in
|
||||
SLIDE_LEFT, // the old view slides out to the left and the new one slides in from the right
|
||||
SLIDE_RIGHT // inverted SLIDE_LEFT
|
||||
};
|
||||
|
||||
// Focus direction when navigating
|
||||
enum class FocusDirection
|
||||
{
|
||||
UP,
|
||||
DOWN,
|
||||
LEFT,
|
||||
RIGHT
|
||||
};
|
||||
|
||||
// View background
|
||||
enum class Background
|
||||
{
|
||||
NONE,
|
||||
SIDEBAR,
|
||||
DEBUG,
|
||||
BACKDROP
|
||||
};
|
||||
|
||||
extern NVGcolor transparent;
|
||||
|
||||
class View;
|
||||
|
||||
typedef Event<View*> GenericEvent;
|
||||
typedef Event<> VoidEvent;
|
||||
|
||||
// Superclass for all the other views
|
||||
// Lifecycle of a view is :
|
||||
// new -> [willAppear -> willDisappear] -> delete
|
||||
//
|
||||
// Users have do to the new, the rest of the lifecycle is taken
|
||||
// care of by the library
|
||||
//
|
||||
// willAppear and willDisappear can be called zero or multiple times
|
||||
// before deletion (in case of a TabLayout for instance)
|
||||
class View
|
||||
{
|
||||
private:
|
||||
Background background = Background::NONE;
|
||||
|
||||
void drawBackground(NVGcontext* vg, FrameContext* ctx, Style* style);
|
||||
void drawHighlight(NVGcontext* vg, ThemeValues* theme, float alpha, Style* style, bool background);
|
||||
|
||||
float highlightAlpha = 0.0f;
|
||||
|
||||
bool dirty = true;
|
||||
|
||||
bool highlightShaking = false;
|
||||
retro_time_t highlightShakeStart;
|
||||
FocusDirection highlightShakeDirection;
|
||||
float highlightShakeAmplitude;
|
||||
|
||||
bool fadeIn = false; // is the fade in animation running?
|
||||
bool forceTranslucent = false;
|
||||
|
||||
ThemeValues* themeOverride = nullptr;
|
||||
|
||||
bool hidden = false;
|
||||
|
||||
std::vector<Action> actions;
|
||||
|
||||
/**
|
||||
* Parent user data, typically the index of the view
|
||||
* in the internal layout structure
|
||||
*/
|
||||
void* parentUserdata = nullptr;
|
||||
|
||||
protected:
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
|
||||
float collapseState = 1.0f;
|
||||
|
||||
bool focused = false;
|
||||
|
||||
View* parent = nullptr;
|
||||
|
||||
GenericEvent focusEvent;
|
||||
|
||||
virtual unsigned getShowAnimationDuration(ViewAnimation animation);
|
||||
|
||||
virtual void getHighlightInsets(unsigned* top, unsigned* right, unsigned* bottom, unsigned* left)
|
||||
{
|
||||
*top = 0;
|
||||
*right = 0;
|
||||
*bottom = 0;
|
||||
*left = 0;
|
||||
}
|
||||
|
||||
virtual void getHighlightMetrics(Style* style, float* cornerRadius)
|
||||
{
|
||||
*cornerRadius = style->Highlight.cornerRadius;
|
||||
}
|
||||
|
||||
virtual bool isHighlightBackgroundEnabled()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Helper functions to apply this view's alpha to a color
|
||||
NVGcolor a(NVGcolor color);
|
||||
NVGpaint a(NVGpaint paint);
|
||||
|
||||
NVGcolor RGB(unsigned r, unsigned g, unsigned b)
|
||||
{
|
||||
return this->a(nvgRGB(r, g, b));
|
||||
}
|
||||
|
||||
NVGcolor RGBA(unsigned r, unsigned g, unsigned b, unsigned a)
|
||||
{
|
||||
return this->a(nvgRGBA(r, g, b, a));
|
||||
}
|
||||
|
||||
NVGcolor RGBf(float r, float g, float b)
|
||||
{
|
||||
return this->a(nvgRGBf(r, g, b));
|
||||
}
|
||||
|
||||
NVGcolor RGBAf(float r, float g, float b, float a)
|
||||
{
|
||||
return this->a(nvgRGBAf(r, g, b, a));
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the hint alpha be animated when
|
||||
* pushing the view?
|
||||
*/
|
||||
virtual bool animateHint()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
void setBoundaries(int x, int y, unsigned width, unsigned height);
|
||||
|
||||
void setBackground(Background background);
|
||||
|
||||
void setWidth(unsigned width);
|
||||
void setHeight(unsigned height);
|
||||
|
||||
void shakeHighlight(FocusDirection direction);
|
||||
|
||||
int getX();
|
||||
int getY();
|
||||
unsigned getWidth();
|
||||
unsigned getHeight(bool includeCollapse = true);
|
||||
|
||||
void setForceTranslucent(bool translucent);
|
||||
|
||||
void setParent(View* parent, void* parentUserdata = nullptr);
|
||||
View* getParent();
|
||||
bool hasParent();
|
||||
|
||||
void* getParentUserData();
|
||||
|
||||
void registerAction(std::string hintText, Key key, ActionListener actionListener, bool hidden = false);
|
||||
void updateActionHint(Key key, std::string hintText);
|
||||
void setActionAvailable(Key key, bool available);
|
||||
|
||||
std::string describe() const { return typeid(*this).name(); }
|
||||
|
||||
const std::vector<Action>& getActions()
|
||||
{
|
||||
return this->actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called each frame
|
||||
* Do not override it to draw your view,
|
||||
* override draw() instead
|
||||
*/
|
||||
virtual void frame(FrameContext* ctx);
|
||||
|
||||
/**
|
||||
* Called by frame() to draw
|
||||
* the view onscreen
|
||||
*/
|
||||
virtual void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) = 0;
|
||||
|
||||
/**
|
||||
* Triggered when the view has been
|
||||
* resized and needs to layout its
|
||||
* children
|
||||
*/
|
||||
virtual void layout(NVGcontext* vg, Style* style, FontStash* stash)
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the view will appear
|
||||
* on screen, before or after layout()
|
||||
*
|
||||
* Can be called if the view has
|
||||
* already appeared, so be careful
|
||||
*/
|
||||
virtual void willAppear(bool resetState = false)
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the view will disappear
|
||||
* from the screen
|
||||
*
|
||||
* Can be called if the view has
|
||||
* already disappeared, so be careful
|
||||
*/
|
||||
virtual void willDisappear(bool resetState = false)
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the show() animation (fade in)
|
||||
* ends
|
||||
*/
|
||||
virtual void onShowAnimationEnd() {};
|
||||
|
||||
/**
|
||||
* Shows the view (fade in animation)
|
||||
*
|
||||
* Called once when the view is
|
||||
* pushed to the view stack
|
||||
*
|
||||
* Not recursive
|
||||
*/
|
||||
virtual void show(std::function<void(void)> cb, bool animate = true, ViewAnimation animation = ViewAnimation::FADE);
|
||||
|
||||
/**
|
||||
* Hides the view in a collapse animation
|
||||
*/
|
||||
void collapse(bool animated = true);
|
||||
|
||||
bool isCollapsed();
|
||||
|
||||
/**
|
||||
* Shows the view in a expand animation (opposite
|
||||
* of collapse)
|
||||
*/
|
||||
void expand(bool animated = true);
|
||||
|
||||
/**
|
||||
* Hides the view (fade out animation)
|
||||
*
|
||||
* Called if another view is pushed
|
||||
* on top of this one
|
||||
*
|
||||
* Not recursive
|
||||
*/
|
||||
virtual void hide(std::function<void(void)> cb, bool animated = true, ViewAnimation animation = ViewAnimation::FADE);
|
||||
|
||||
bool isHidden();
|
||||
|
||||
/**
|
||||
* Calls layout() on next frame
|
||||
* unless immediate is true in which case
|
||||
* it's called immediately
|
||||
*/
|
||||
void invalidate(bool immediate = false);
|
||||
|
||||
/**
|
||||
* Is this view translucent?
|
||||
*
|
||||
* If you override it please return
|
||||
* <value> || View::isTranslucent()
|
||||
* to keep the fadeIn transition
|
||||
*/
|
||||
virtual bool isTranslucent()
|
||||
{
|
||||
return fadeIn || forceTranslucent;
|
||||
}
|
||||
|
||||
bool isFocused();
|
||||
|
||||
/**
|
||||
* Returns the default view to focus when focusing this view
|
||||
* Typically the view itself or one of its children
|
||||
*
|
||||
* Returning nullptr means that the view is not focusable
|
||||
* (and neither are its children)
|
||||
*
|
||||
* When pressing a key, the flow is :
|
||||
* 1. starting from the currently focused view's parent, traverse the tree upwards and
|
||||
* repeatidly call getNextFocus() on every view until we find a next view to focus or meet the end of the tree
|
||||
* 2. if a view is found, getNextFocus() will internally call getDefaultFocus() for the selected child
|
||||
* 3. give focus to the result, if it exists
|
||||
*/
|
||||
virtual View* getDefaultFocus()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next view to focus given the requested direction
|
||||
* and the currently focused view (as parent user data)
|
||||
*
|
||||
* Returning nullptr means that there is no next view to focus
|
||||
* in that direction - getNextFocus will then be called on our
|
||||
* parent if any
|
||||
*/
|
||||
virtual View* getNextFocus(FocusDirection direction, void* parentUserdata)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when focus is gained
|
||||
*/
|
||||
virtual void onFocusGained();
|
||||
|
||||
/**
|
||||
* Fired when focus is lost
|
||||
*/
|
||||
virtual void onFocusLost();
|
||||
|
||||
/**
|
||||
* Fired when focus is gained on one of this view's children
|
||||
*/
|
||||
virtual void onChildFocusGained(View* child)
|
||||
{
|
||||
if (this->hasParent())
|
||||
this->getParent()->onChildFocusGained(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when focus is gained on one of this view's children
|
||||
*/
|
||||
virtual void onChildFocusLost(View* child)
|
||||
{
|
||||
if (this->hasParent())
|
||||
this->getParent()->onChildFocusLost(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when the window size changes
|
||||
* Not guaranteed to be called before or after layout()
|
||||
*/
|
||||
virtual void onWindowSizeChanged()
|
||||
{
|
||||
// Nothing by default
|
||||
}
|
||||
|
||||
GenericEvent* getFocusEvent();
|
||||
|
||||
float alpha = 1.0f;
|
||||
|
||||
virtual float getAlpha(bool child = false);
|
||||
|
||||
/**
|
||||
* Forces this view and its children to use
|
||||
* the specified theme variant
|
||||
*/
|
||||
void overrideThemeVariant(ThemeValues* newTheme);
|
||||
|
||||
virtual ~View();
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
933
lib/borealis/library/lib/animations.cpp
Normal file
933
lib/borealis/library/lib/animations.cpp
Normal file
@@ -0,0 +1,933 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Borealis, a Nintendo Switch UI Library
|
||||
* Copyright (C) 2014-2018 - Jean-André Santoni
|
||||
* Copyright (C) 2011-2018 - Daniel De Matteis
|
||||
* Copyright (C) 2019 - natinusala
|
||||
* Copyright (C) 2019 - p-sam
|
||||
*
|
||||
* RetroArch 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 Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch 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 RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <compat/strl.h>
|
||||
#include <encodings/utf.h>
|
||||
#include <features/features_cpu.h>
|
||||
#include <math.h>
|
||||
#include <retro_assert.h>
|
||||
#include <retro_math.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <string/stdstring.h>
|
||||
|
||||
#include <borealis/animations.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
struct tween
|
||||
{
|
||||
float duration;
|
||||
float running_since;
|
||||
float initial_value;
|
||||
float target_value;
|
||||
float* subject;
|
||||
uintptr_t tag;
|
||||
easing_cb easing;
|
||||
tween_cb cb;
|
||||
tween_cb tick;
|
||||
void* userdata;
|
||||
bool deleted;
|
||||
};
|
||||
|
||||
struct menu_animation
|
||||
{
|
||||
std::vector<tween> list;
|
||||
std::vector<tween> pending;
|
||||
bool pending_deletes;
|
||||
bool in_update;
|
||||
};
|
||||
|
||||
typedef struct menu_animation menu_animation_t;
|
||||
|
||||
#define TICKER_SPEED 333
|
||||
#define TICKER_SLOW_SPEED 1600
|
||||
|
||||
static const char ticker_spacer_default[] = " | ";
|
||||
|
||||
static menu_animation_t anim;
|
||||
static retro_time_t cur_time = 0;
|
||||
static retro_time_t old_time = 0;
|
||||
static uint64_t ticker_idx = 0; /* updated every TICKER_SPEED ms */
|
||||
static uint64_t ticker_slow_idx = 0; /* updated every TICKER_SLOW_SPEED ms */
|
||||
static float delta_time = 0.0f;
|
||||
static bool animation_is_active = false;
|
||||
static bool ticker_is_active = false;
|
||||
|
||||
static double highlight_gradient_x = 0.0f;
|
||||
static double highlight_gradient_y = 0.0f;
|
||||
static double highlight_color = 0.0f;
|
||||
|
||||
/* from https://github.com/kikito/tween.lua/blob/master/tween.lua */
|
||||
|
||||
static float easing_linear(float t, float b, float c, float d)
|
||||
{
|
||||
return c * t / d + b;
|
||||
}
|
||||
|
||||
static float easing_in_out_quad(float t, float b, float c, float d)
|
||||
{
|
||||
t = t / d * 2;
|
||||
if (t < 1)
|
||||
return c / 2 * pow(t, 2) + b;
|
||||
return -c / 2 * ((t - 1) * (t - 3) - 1) + b;
|
||||
}
|
||||
|
||||
static float easing_in_quad(float t, float b, float c, float d)
|
||||
{
|
||||
return c * pow(t / d, 2) + b;
|
||||
}
|
||||
|
||||
static float easing_out_quad(float t, float b, float c, float d)
|
||||
{
|
||||
t = t / d;
|
||||
return -c * t * (t - 2) + b;
|
||||
}
|
||||
|
||||
static float easing_out_in_quad(float t, float b, float c, float d)
|
||||
{
|
||||
if (t < d / 2)
|
||||
return easing_out_quad(t * 2, b, c / 2, d);
|
||||
return easing_in_quad((t * 2) - d, b + c / 2, c / 2, d);
|
||||
}
|
||||
|
||||
static float easing_in_cubic(float t, float b, float c, float d)
|
||||
{
|
||||
return c * pow(t / d, 3) + b;
|
||||
}
|
||||
|
||||
static float easing_out_cubic(float t, float b, float c, float d)
|
||||
{
|
||||
return c * (pow(t / d - 1, 3) + 1) + b;
|
||||
}
|
||||
|
||||
static float easing_in_out_cubic(float t, float b, float c, float d)
|
||||
{
|
||||
t = t / d * 2;
|
||||
if (t < 1)
|
||||
return c / 2 * t * t * t + b;
|
||||
t = t - 2;
|
||||
return c / 2 * (t * t * t + 2) + b;
|
||||
}
|
||||
|
||||
static float easing_out_in_cubic(float t, float b, float c, float d)
|
||||
{
|
||||
if (t < d / 2)
|
||||
return easing_out_cubic(t * 2, b, c / 2, d);
|
||||
return easing_in_cubic((t * 2) - d, b + c / 2, c / 2, d);
|
||||
}
|
||||
|
||||
static float easing_in_quart(float t, float b, float c, float d)
|
||||
{
|
||||
return c * pow(t / d, 4) + b;
|
||||
}
|
||||
|
||||
static float easing_out_quart(float t, float b, float c, float d)
|
||||
{
|
||||
return -c * (pow(t / d - 1, 4) - 1) + b;
|
||||
}
|
||||
|
||||
static float easing_in_out_quart(float t, float b, float c, float d)
|
||||
{
|
||||
t = t / d * 2;
|
||||
if (t < 1)
|
||||
return c / 2 * pow(t, 4) + b;
|
||||
return -c / 2 * (pow(t - 2, 4) - 2) + b;
|
||||
}
|
||||
|
||||
static float easing_out_in_quart(float t, float b, float c, float d)
|
||||
{
|
||||
if (t < d / 2)
|
||||
return easing_out_quart(t * 2, b, c / 2, d);
|
||||
return easing_in_quart((t * 2) - d, b + c / 2, c / 2, d);
|
||||
}
|
||||
|
||||
static float easing_in_quint(float t, float b, float c, float d)
|
||||
{
|
||||
return c * pow(t / d, 5) + b;
|
||||
}
|
||||
|
||||
static float easing_out_quint(float t, float b, float c, float d)
|
||||
{
|
||||
return c * (pow(t / d - 1, 5) + 1) + b;
|
||||
}
|
||||
|
||||
static float easing_in_out_quint(float t, float b, float c, float d)
|
||||
{
|
||||
t = t / d * 2;
|
||||
if (t < 1)
|
||||
return c / 2 * pow(t, 5) + b;
|
||||
return c / 2 * (pow(t - 2, 5) + 2) + b;
|
||||
}
|
||||
|
||||
static float easing_out_in_quint(float t, float b, float c, float d)
|
||||
{
|
||||
if (t < d / 2)
|
||||
return easing_out_quint(t * 2, b, c / 2, d);
|
||||
return easing_in_quint((t * 2) - d, b + c / 2, c / 2, d);
|
||||
}
|
||||
|
||||
static float easing_in_sine(float t, float b, float c, float d)
|
||||
{
|
||||
return -c * cos(t / d * (M_PI / 2)) + c + b;
|
||||
}
|
||||
|
||||
static float easing_out_sine(float t, float b, float c, float d)
|
||||
{
|
||||
return c * sin(t / d * (M_PI / 2)) + b;
|
||||
}
|
||||
|
||||
static float easing_in_out_sine(float t, float b, float c, float d)
|
||||
{
|
||||
return -c / 2 * (cos(M_PI * t / d) - 1) + b;
|
||||
}
|
||||
|
||||
static float easing_out_in_sine(float t, float b, float c, float d)
|
||||
{
|
||||
if (t < d / 2)
|
||||
return easing_out_sine(t * 2, b, c / 2, d);
|
||||
return easing_in_sine((t * 2) - d, b + c / 2, c / 2, d);
|
||||
}
|
||||
|
||||
static float easing_in_expo(float t, float b, float c, float d)
|
||||
{
|
||||
if (t == 0)
|
||||
return b;
|
||||
return c * powf(2, 10 * (t / d - 1)) + b - c * 0.001;
|
||||
}
|
||||
|
||||
static float easing_out_expo(float t, float b, float c, float d)
|
||||
{
|
||||
if (t == d)
|
||||
return b + c;
|
||||
return c * 1.001 * (-powf(2, -10 * t / d) + 1) + b;
|
||||
}
|
||||
|
||||
static float easing_in_out_expo(float t, float b, float c, float d)
|
||||
{
|
||||
if (t == 0)
|
||||
return b;
|
||||
if (t == d)
|
||||
return b + c;
|
||||
t = t / d * 2;
|
||||
if (t < 1)
|
||||
return c / 2 * powf(2, 10 * (t - 1)) + b - c * 0.0005;
|
||||
return c / 2 * 1.0005 * (-powf(2, -10 * (t - 1)) + 2) + b;
|
||||
}
|
||||
|
||||
static float easing_out_in_expo(float t, float b, float c, float d)
|
||||
{
|
||||
if (t < d / 2)
|
||||
return easing_out_expo(t * 2, b, c / 2, d);
|
||||
return easing_in_expo((t * 2) - d, b + c / 2, c / 2, d);
|
||||
}
|
||||
|
||||
static float easing_in_circ(float t, float b, float c, float d)
|
||||
{
|
||||
return (-c * (sqrt(1 - powf(t / d, 2)) - 1) + b);
|
||||
}
|
||||
|
||||
static float easing_out_circ(float t, float b, float c, float d)
|
||||
{
|
||||
return (c * sqrt(1 - powf(t / d - 1, 2)) + b);
|
||||
}
|
||||
|
||||
static float easing_in_out_circ(float t, float b, float c, float d)
|
||||
{
|
||||
t = t / d * 2;
|
||||
if (t < 1)
|
||||
return -c / 2 * (sqrt(1 - t * t) - 1) + b;
|
||||
t = t - 2;
|
||||
return c / 2 * (sqrt(1 - t * t) + 1) + b;
|
||||
}
|
||||
|
||||
static float easing_out_in_circ(float t, float b, float c, float d)
|
||||
{
|
||||
if (t < d / 2)
|
||||
return easing_out_circ(t * 2, b, c / 2, d);
|
||||
return easing_in_circ((t * 2) - d, b + c / 2, c / 2, d);
|
||||
}
|
||||
|
||||
static float easing_out_bounce(float t, float b, float c, float d)
|
||||
{
|
||||
t = t / d;
|
||||
if (t < 1 / 2.75)
|
||||
return c * (7.5625 * t * t) + b;
|
||||
if (t < 2 / 2.75)
|
||||
{
|
||||
t = t - (1.5 / 2.75);
|
||||
return c * (7.5625 * t * t + 0.75) + b;
|
||||
}
|
||||
else if (t < 2.5 / 2.75)
|
||||
{
|
||||
t = t - (2.25 / 2.75);
|
||||
return c * (7.5625 * t * t + 0.9375) + b;
|
||||
}
|
||||
t = t - (2.625 / 2.75);
|
||||
return c * (7.5625 * t * t + 0.984375) + b;
|
||||
}
|
||||
|
||||
static float easing_in_bounce(float t, float b, float c, float d)
|
||||
{
|
||||
return c - easing_out_bounce(d - t, 0, c, d) + b;
|
||||
}
|
||||
|
||||
static float easing_in_out_bounce(float t, float b, float c, float d)
|
||||
{
|
||||
if (t < d / 2)
|
||||
return easing_in_bounce(t * 2, 0, c, d) * 0.5 + b;
|
||||
return easing_out_bounce(t * 2 - d, 0, c, d) * 0.5 + c * .5 + b;
|
||||
}
|
||||
|
||||
static float easing_out_in_bounce(float t, float b, float c, float d)
|
||||
{
|
||||
if (t < d / 2)
|
||||
return easing_out_bounce(t * 2, b, c / 2, d);
|
||||
return easing_in_bounce((t * 2) - d, b + c / 2, c / 2, d);
|
||||
}
|
||||
|
||||
static void menu_animation_ticker_generic(uint64_t idx,
|
||||
size_t max_width, size_t* offset, size_t* width)
|
||||
{
|
||||
int ticker_period = (int)(2 * (*width - max_width) + 4);
|
||||
int phase = idx % ticker_period;
|
||||
|
||||
int phase_left_stop = 2;
|
||||
int phase_left_moving = (int)(phase_left_stop + (*width - max_width));
|
||||
int phase_right_stop = phase_left_moving + 2;
|
||||
|
||||
int left_offset = phase - phase_left_stop;
|
||||
int right_offset = (int)((*width - max_width) - (phase - phase_right_stop));
|
||||
|
||||
if (phase < phase_left_stop)
|
||||
*offset = 0;
|
||||
else if (phase < phase_left_moving)
|
||||
*offset = left_offset;
|
||||
else if (phase < phase_right_stop)
|
||||
*offset = *width - max_width;
|
||||
else
|
||||
*offset = right_offset;
|
||||
|
||||
*width = max_width;
|
||||
}
|
||||
|
||||
static void menu_animation_ticker_loop(uint64_t idx,
|
||||
size_t max_width, size_t str_width, size_t spacer_width,
|
||||
size_t* offset1, size_t* width1,
|
||||
size_t* offset2, size_t* width2,
|
||||
size_t* offset3, size_t* width3)
|
||||
{
|
||||
int ticker_period = (int)(str_width + spacer_width);
|
||||
int phase = idx % ticker_period;
|
||||
|
||||
/* Output offsets/widths are unsigned size_t, but it's
|
||||
* easier to perform the required calculations with ints,
|
||||
* so create some temporary variables... */
|
||||
int offset;
|
||||
int width;
|
||||
|
||||
/* Looping text is composed of up to three strings,
|
||||
* where std::string 1 and 2 are different regions of the
|
||||
* source text and std::string 2 is a spacer:
|
||||
*
|
||||
* |-----max_width-----|
|
||||
* [std::string 1][std::string 2][std::string 3]
|
||||
*
|
||||
* The following implementation could probably be optimised,
|
||||
* but any performance gains would be trivial compared with
|
||||
* all the std::string manipulation that has to happen afterwards...
|
||||
*/
|
||||
|
||||
/* String 1 */
|
||||
offset = (phase < (int)str_width) ? phase : 0;
|
||||
width = (int)(str_width - phase);
|
||||
width = (width < 0) ? 0 : width;
|
||||
width = (width > (int)max_width) ? max_width : width;
|
||||
|
||||
*offset1 = offset;
|
||||
*width1 = width;
|
||||
|
||||
/* String 2 */
|
||||
offset = (int)(phase - str_width);
|
||||
offset = offset < 0 ? 0 : offset;
|
||||
width = (int)(max_width - *width1);
|
||||
width = (width > (int)spacer_width) ? spacer_width : width;
|
||||
width = width - offset;
|
||||
|
||||
*offset2 = offset;
|
||||
*width2 = width;
|
||||
|
||||
/* String 3 */
|
||||
width = max_width - (*width1 + *width2);
|
||||
width = width < 0 ? 0 : width;
|
||||
|
||||
/* Note: offset is always zero here so offset3 is
|
||||
* unnecessary - but include it anyway to preserve
|
||||
* symmetry... */
|
||||
*offset3 = 0;
|
||||
*width3 = width;
|
||||
}
|
||||
|
||||
void menu_animation_init(void)
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void menu_animation_free(void)
|
||||
{
|
||||
anim.list.clear();
|
||||
anim.pending.clear();
|
||||
|
||||
anim.in_update = false;
|
||||
anim.pending_deletes = false;
|
||||
}
|
||||
|
||||
static void menu_delayed_animation_cb(void* userdata)
|
||||
{
|
||||
menu_delayed_animation_t* delayed_animation = (menu_delayed_animation_t*)userdata;
|
||||
|
||||
menu_animation_push(&delayed_animation->entry);
|
||||
|
||||
free(delayed_animation);
|
||||
}
|
||||
|
||||
void menu_animation_push_delayed(unsigned delay, menu_animation_ctx_entry_t* entry)
|
||||
{
|
||||
menu_timer_ctx_entry_t timer_entry;
|
||||
menu_delayed_animation_t* delayed_animation = (menu_delayed_animation_t*)malloc(sizeof(menu_delayed_animation_t));
|
||||
|
||||
delayed_animation->entry.cb = entry->cb;
|
||||
delayed_animation->entry.duration = entry->duration;
|
||||
delayed_animation->entry.easing_enum = entry->easing_enum;
|
||||
delayed_animation->entry.subject = entry->subject;
|
||||
delayed_animation->entry.tag = entry->tag;
|
||||
delayed_animation->entry.target_value = entry->target_value;
|
||||
delayed_animation->entry.tick = entry->tick;
|
||||
delayed_animation->entry.userdata = entry->userdata;
|
||||
|
||||
timer_entry.cb = menu_delayed_animation_cb;
|
||||
timer_entry.tick = NULL;
|
||||
timer_entry.duration = delay;
|
||||
timer_entry.userdata = delayed_animation;
|
||||
|
||||
menu_timer_start(&delayed_animation->timer, &timer_entry);
|
||||
}
|
||||
|
||||
bool menu_animation_push(menu_animation_ctx_entry_t* entry)
|
||||
{
|
||||
struct tween t;
|
||||
|
||||
t.duration = entry->duration;
|
||||
t.running_since = 0;
|
||||
t.initial_value = *entry->subject;
|
||||
t.target_value = entry->target_value;
|
||||
t.subject = entry->subject;
|
||||
t.tag = entry->tag;
|
||||
t.cb = entry->cb;
|
||||
t.tick = entry->tick;
|
||||
t.userdata = entry->userdata;
|
||||
t.easing = NULL;
|
||||
t.deleted = false;
|
||||
|
||||
switch (entry->easing_enum)
|
||||
{
|
||||
case EASING_LINEAR:
|
||||
t.easing = &easing_linear;
|
||||
break;
|
||||
/* Quad */
|
||||
case EASING_IN_QUAD:
|
||||
t.easing = &easing_in_quad;
|
||||
break;
|
||||
case EASING_OUT_QUAD:
|
||||
t.easing = &easing_out_quad;
|
||||
break;
|
||||
case EASING_IN_OUT_QUAD:
|
||||
t.easing = &easing_in_out_quad;
|
||||
break;
|
||||
case EASING_OUT_IN_QUAD:
|
||||
t.easing = &easing_out_in_quad;
|
||||
break;
|
||||
/* Cubic */
|
||||
case EASING_IN_CUBIC:
|
||||
t.easing = &easing_in_cubic;
|
||||
break;
|
||||
case EASING_OUT_CUBIC:
|
||||
t.easing = &easing_out_cubic;
|
||||
break;
|
||||
case EASING_IN_OUT_CUBIC:
|
||||
t.easing = &easing_in_out_cubic;
|
||||
break;
|
||||
case EASING_OUT_IN_CUBIC:
|
||||
t.easing = &easing_out_in_cubic;
|
||||
break;
|
||||
/* Quart */
|
||||
case EASING_IN_QUART:
|
||||
t.easing = &easing_in_quart;
|
||||
break;
|
||||
case EASING_OUT_QUART:
|
||||
t.easing = &easing_out_quart;
|
||||
break;
|
||||
case EASING_IN_OUT_QUART:
|
||||
t.easing = &easing_in_out_quart;
|
||||
break;
|
||||
case EASING_OUT_IN_QUART:
|
||||
t.easing = &easing_out_in_quart;
|
||||
break;
|
||||
/* Quint */
|
||||
case EASING_IN_QUINT:
|
||||
t.easing = &easing_in_quint;
|
||||
break;
|
||||
case EASING_OUT_QUINT:
|
||||
t.easing = &easing_out_quint;
|
||||
break;
|
||||
case EASING_IN_OUT_QUINT:
|
||||
t.easing = &easing_in_out_quint;
|
||||
break;
|
||||
case EASING_OUT_IN_QUINT:
|
||||
t.easing = &easing_out_in_quint;
|
||||
break;
|
||||
/* Sine */
|
||||
case EASING_IN_SINE:
|
||||
t.easing = &easing_in_sine;
|
||||
break;
|
||||
case EASING_OUT_SINE:
|
||||
t.easing = &easing_out_sine;
|
||||
break;
|
||||
case EASING_IN_OUT_SINE:
|
||||
t.easing = &easing_in_out_sine;
|
||||
break;
|
||||
case EASING_OUT_IN_SINE:
|
||||
t.easing = &easing_out_in_sine;
|
||||
break;
|
||||
/* Expo */
|
||||
case EASING_IN_EXPO:
|
||||
t.easing = &easing_in_expo;
|
||||
break;
|
||||
case EASING_OUT_EXPO:
|
||||
t.easing = &easing_out_expo;
|
||||
break;
|
||||
case EASING_IN_OUT_EXPO:
|
||||
t.easing = &easing_in_out_expo;
|
||||
break;
|
||||
case EASING_OUT_IN_EXPO:
|
||||
t.easing = &easing_out_in_expo;
|
||||
break;
|
||||
/* Circ */
|
||||
case EASING_IN_CIRC:
|
||||
t.easing = &easing_in_circ;
|
||||
break;
|
||||
case EASING_OUT_CIRC:
|
||||
t.easing = &easing_out_circ;
|
||||
break;
|
||||
case EASING_IN_OUT_CIRC:
|
||||
t.easing = &easing_in_out_circ;
|
||||
break;
|
||||
case EASING_OUT_IN_CIRC:
|
||||
t.easing = &easing_out_in_circ;
|
||||
break;
|
||||
/* Bounce */
|
||||
case EASING_IN_BOUNCE:
|
||||
t.easing = &easing_in_bounce;
|
||||
break;
|
||||
case EASING_OUT_BOUNCE:
|
||||
t.easing = &easing_out_bounce;
|
||||
break;
|
||||
case EASING_IN_OUT_BOUNCE:
|
||||
t.easing = &easing_in_out_bounce;
|
||||
break;
|
||||
case EASING_OUT_IN_BOUNCE:
|
||||
t.easing = &easing_out_in_bounce;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* ignore born dead tweens */
|
||||
if (!t.easing || t.duration == 0 || t.initial_value == t.target_value)
|
||||
return false;
|
||||
|
||||
if (anim.in_update)
|
||||
anim.pending.push_back(t);
|
||||
else
|
||||
anim.list.push_back(t);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void menu_animation_get_highlight(float* gradient_x, float* gradient_y, float* color)
|
||||
{
|
||||
if (gradient_x)
|
||||
*gradient_x = (float)highlight_gradient_x;
|
||||
|
||||
if (gradient_y)
|
||||
*gradient_y = (float)highlight_gradient_y;
|
||||
|
||||
if (color)
|
||||
*color = (float)highlight_color;
|
||||
}
|
||||
|
||||
#define HIGHLIGHT_SPEED 350.0
|
||||
|
||||
static void menu_animation_update_time(bool timedate_enable)
|
||||
{
|
||||
static retro_time_t
|
||||
last_clock_update
|
||||
= 0;
|
||||
static retro_time_t
|
||||
last_ticker_update
|
||||
= 0;
|
||||
static retro_time_t
|
||||
last_ticker_slow_update
|
||||
= 0;
|
||||
|
||||
/* Adjust ticker speed */
|
||||
float speed_factor = 1.0f;
|
||||
unsigned ticker_speed = (unsigned)(((float)TICKER_SPEED / speed_factor) + 0.5);
|
||||
unsigned ticker_slow_speed = (unsigned)(((float)TICKER_SLOW_SPEED / speed_factor) + 0.5);
|
||||
|
||||
cur_time = cpu_features_get_time_usec() / 1000;
|
||||
delta_time = old_time == 0 ? 0 : cur_time - old_time;
|
||||
|
||||
old_time = cur_time;
|
||||
|
||||
highlight_gradient_x = (cos((double)cur_time / HIGHLIGHT_SPEED / 3.0) + 1.0) / 2.0;
|
||||
highlight_gradient_y = (sin((double)cur_time / HIGHLIGHT_SPEED / 3.0) + 1.0) / 2.0;
|
||||
highlight_color = (sin((double)cur_time / HIGHLIGHT_SPEED * 2.0) + 1.0) / 2.0;
|
||||
|
||||
if (((cur_time - last_clock_update) > 1000)
|
||||
&& timedate_enable)
|
||||
{
|
||||
animation_is_active = true;
|
||||
last_clock_update = cur_time;
|
||||
}
|
||||
|
||||
if (ticker_is_active
|
||||
&& cur_time - last_ticker_update >= ticker_speed)
|
||||
{
|
||||
ticker_idx++;
|
||||
last_ticker_update = cur_time;
|
||||
}
|
||||
|
||||
if (ticker_is_active
|
||||
&& cur_time - last_ticker_slow_update >= ticker_slow_speed)
|
||||
{
|
||||
ticker_slow_idx++;
|
||||
last_ticker_slow_update = cur_time;
|
||||
}
|
||||
}
|
||||
|
||||
bool menu_animation_update(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
menu_animation_update_time(false);
|
||||
|
||||
anim.in_update = true;
|
||||
anim.pending_deletes = false;
|
||||
|
||||
for (i = 0; i < anim.list.size(); i++)
|
||||
{
|
||||
struct tween* tween = &anim.list[i];
|
||||
tween->running_since += delta_time;
|
||||
|
||||
*tween->subject = tween->easing(
|
||||
tween->running_since,
|
||||
tween->initial_value,
|
||||
tween->target_value - tween->initial_value,
|
||||
tween->duration);
|
||||
|
||||
if (tween->tick)
|
||||
tween->tick(tween->userdata);
|
||||
|
||||
if (tween->running_since >= tween->duration)
|
||||
{
|
||||
*tween->subject = tween->target_value;
|
||||
|
||||
if (tween->cb)
|
||||
tween->cb(tween->userdata);
|
||||
|
||||
anim.list.erase(anim.list.begin() + i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
if (anim.pending_deletes)
|
||||
{
|
||||
for (i = 0; i < anim.list.size(); i++)
|
||||
{
|
||||
struct tween* tween = &anim.list[i];
|
||||
if (tween->deleted)
|
||||
{
|
||||
anim.list.erase(anim.list.begin() + i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
anim.pending_deletes = false;
|
||||
}
|
||||
|
||||
if (anim.pending.size() > 0)
|
||||
{
|
||||
anim.list.insert(anim.list.begin(), anim.pending.begin(), anim.pending.end());
|
||||
anim.pending.clear();
|
||||
}
|
||||
|
||||
anim.in_update = false;
|
||||
animation_is_active = anim.list.size() > 0;
|
||||
|
||||
return animation_is_active;
|
||||
}
|
||||
|
||||
bool menu_animation_ticker(menu_animation_ctx_ticker_t* ticker)
|
||||
{
|
||||
size_t str_len = utf8len(ticker->str);
|
||||
|
||||
if (!ticker->spacer)
|
||||
ticker->spacer = ticker_spacer_default;
|
||||
|
||||
if ((size_t)str_len <= ticker->len)
|
||||
{
|
||||
utf8cpy(ticker->s,
|
||||
PATH_MAX_LENGTH,
|
||||
ticker->str,
|
||||
ticker->len);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ticker->selected)
|
||||
{
|
||||
utf8cpy(ticker->s, PATH_MAX_LENGTH, ticker->str, ticker->len - 3);
|
||||
strlcat(ticker->s, "...", PATH_MAX_LENGTH);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Note: If we reach this point then str_len > ticker->len
|
||||
* (previously had an unecessary 'if (str_len > ticker->len)'
|
||||
* check here...) */
|
||||
switch (ticker->type_enum)
|
||||
{
|
||||
case TICKER_TYPE_LOOP:
|
||||
{
|
||||
size_t offset1, offset2, offset3;
|
||||
size_t width1, width2, width3;
|
||||
|
||||
/* Horribly oversized temporary buffer
|
||||
* > utf8 support makes this whole thing incredibly
|
||||
* ugly/inefficient. Not much we can do about it... */
|
||||
char tmp[PATH_MAX_LENGTH];
|
||||
|
||||
tmp[0] = '\0';
|
||||
ticker->s[0] = '\0';
|
||||
|
||||
menu_animation_ticker_loop(
|
||||
ticker->idx,
|
||||
ticker->len,
|
||||
str_len, utf8len(ticker->spacer),
|
||||
&offset1, &width1,
|
||||
&offset2, &width2,
|
||||
&offset3, &width3);
|
||||
|
||||
if (width1 > 0)
|
||||
{
|
||||
utf8cpy(
|
||||
ticker->s,
|
||||
PATH_MAX_LENGTH,
|
||||
utf8skip(ticker->str, offset1),
|
||||
width1);
|
||||
}
|
||||
|
||||
if (width2 > 0)
|
||||
{
|
||||
utf8cpy(
|
||||
tmp,
|
||||
PATH_MAX_LENGTH,
|
||||
utf8skip(ticker->spacer, offset2),
|
||||
width2);
|
||||
|
||||
strlcat(ticker->s, tmp, PATH_MAX_LENGTH);
|
||||
}
|
||||
|
||||
if (width3 > 0)
|
||||
{
|
||||
utf8cpy(
|
||||
tmp,
|
||||
PATH_MAX_LENGTH,
|
||||
utf8skip(ticker->str, offset3),
|
||||
width3);
|
||||
|
||||
strlcat(ticker->s, tmp, PATH_MAX_LENGTH);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case TICKER_TYPE_BOUNCE:
|
||||
default:
|
||||
{
|
||||
size_t offset = 0;
|
||||
|
||||
menu_animation_ticker_generic(
|
||||
ticker->idx,
|
||||
ticker->len,
|
||||
&offset,
|
||||
&str_len);
|
||||
|
||||
utf8cpy(
|
||||
ticker->s,
|
||||
PATH_MAX_LENGTH,
|
||||
utf8skip(ticker->str, offset),
|
||||
str_len);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ticker_is_active = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool menu_animation_is_active(void)
|
||||
{
|
||||
return animation_is_active || ticker_is_active;
|
||||
}
|
||||
|
||||
bool menu_animation_kill_by_tag(menu_animation_ctx_tag* tag)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (!tag || *tag == (uintptr_t)-1)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < anim.list.size(); ++i)
|
||||
{
|
||||
struct tween* t = &anim.list[i];
|
||||
if (t->tag != *tag)
|
||||
continue;
|
||||
|
||||
if (anim.in_update)
|
||||
{
|
||||
t->deleted = true;
|
||||
anim.pending_deletes = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
anim.list.erase(anim.list.begin() + i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void menu_animation_kill_by_subject(menu_animation_ctx_subject_t* subject)
|
||||
{
|
||||
unsigned i, j, killed = 0;
|
||||
float** sub = (float**)subject->data;
|
||||
|
||||
for (i = 0; i < anim.list.size() && killed < subject->count; ++i)
|
||||
{
|
||||
struct tween* t = &anim.list[i];
|
||||
|
||||
for (j = 0; j < subject->count; ++j)
|
||||
{
|
||||
if (t->subject != sub[j])
|
||||
continue;
|
||||
|
||||
if (anim.in_update)
|
||||
{
|
||||
t->deleted = true;
|
||||
anim.pending_deletes = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
anim.list.erase(anim.list.begin() + i);
|
||||
--i;
|
||||
}
|
||||
|
||||
killed++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float menu_animation_get_delta_time(void)
|
||||
{
|
||||
return delta_time;
|
||||
}
|
||||
|
||||
bool menu_animation_ctl(enum menu_animation_ctl_state state, void* data)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case MENU_ANIMATION_CTL_CLEAR_ACTIVE:
|
||||
animation_is_active = false;
|
||||
ticker_is_active = false;
|
||||
break;
|
||||
case MENU_ANIMATION_CTL_SET_ACTIVE:
|
||||
animation_is_active = true;
|
||||
ticker_is_active = true;
|
||||
break;
|
||||
case MENU_ANIMATION_CTL_NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void menu_timer_start(menu_timer_t* timer, menu_timer_ctx_entry_t* timer_entry)
|
||||
{
|
||||
menu_animation_ctx_entry_t entry;
|
||||
menu_animation_ctx_tag tag = (uintptr_t)timer;
|
||||
|
||||
menu_timer_kill(timer);
|
||||
|
||||
*timer = 0.0f;
|
||||
|
||||
entry.easing_enum = EASING_LINEAR;
|
||||
entry.tag = tag;
|
||||
entry.duration = timer_entry->duration;
|
||||
entry.target_value = 1.0f;
|
||||
entry.subject = timer;
|
||||
entry.cb = timer_entry->cb;
|
||||
entry.tick = timer_entry->tick;
|
||||
entry.userdata = timer_entry->userdata;
|
||||
|
||||
menu_animation_push(&entry);
|
||||
}
|
||||
|
||||
void menu_timer_kill(menu_timer_t* timer)
|
||||
{
|
||||
menu_animation_ctx_tag tag = (uintptr_t)timer;
|
||||
menu_animation_kill_by_tag(&tag);
|
||||
}
|
||||
|
||||
uint64_t menu_animation_get_ticker_idx(void)
|
||||
{
|
||||
return ticker_idx;
|
||||
}
|
||||
|
||||
uint64_t menu_animation_get_ticker_slow_idx(void)
|
||||
{
|
||||
return ticker_slow_idx;
|
||||
}
|
||||
|
||||
} // namespace brls
|
||||
414
lib/borealis/library/lib/applet_frame.cpp
Normal file
414
lib/borealis/library/lib/applet_frame.cpp
Normal file
@@ -0,0 +1,414 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <borealis/applet_frame.hpp>
|
||||
#include <borealis/application.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
AppletFrame::AppletFrame(bool padLeft, bool padRight)
|
||||
{
|
||||
Style* style = Application::getStyle();
|
||||
|
||||
if (padLeft)
|
||||
this->leftPadding = style->AppletFrame.separatorSpacing;
|
||||
|
||||
if (padRight)
|
||||
this->rightPadding = style->AppletFrame.separatorSpacing;
|
||||
|
||||
this->hint = new Hint();
|
||||
this->hint->setParent(this);
|
||||
|
||||
this->registerAction("Back", Key::B, [this] { return this->onCancel(); });
|
||||
}
|
||||
|
||||
void AppletFrame::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx)
|
||||
{
|
||||
// Text
|
||||
if (this->headerStyle == HeaderStyle::REGULAR)
|
||||
{
|
||||
// Title
|
||||
NVGcolor titleColor = a(ctx->theme->textColor);
|
||||
|
||||
if (this->contentView)
|
||||
titleColor.a *= this->contentView->getAlpha();
|
||||
|
||||
nvgFillColor(vg, titleColor);
|
||||
nvgFontSize(vg, style->AppletFrame.titleSize);
|
||||
nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
|
||||
nvgFontFaceId(vg, ctx->fontStash->regular);
|
||||
nvgBeginPath(vg);
|
||||
nvgText(vg, x + style->AppletFrame.titleStart, y + style->AppletFrame.headerHeightRegular / 2 + style->AppletFrame.titleOffset, this->title.c_str(), nullptr);
|
||||
|
||||
// Header
|
||||
nvgBeginPath(vg);
|
||||
nvgFillColor(vg, a(ctx->theme->textColor));
|
||||
nvgRect(vg, x + style->AppletFrame.separatorSpacing, y + style->AppletFrame.headerHeightRegular - 1, width - style->AppletFrame.separatorSpacing * 2, 1);
|
||||
nvgFill(vg);
|
||||
}
|
||||
else if (this->headerStyle == HeaderStyle::POPUP)
|
||||
{
|
||||
// Header Text
|
||||
nvgBeginPath(vg);
|
||||
nvgFillColor(vg, a(ctx->theme->textColor));
|
||||
nvgFontFaceId(vg, ctx->fontStash->regular);
|
||||
nvgFontSize(vg, style->PopupFrame.headerFontSize);
|
||||
nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
|
||||
nvgText(vg, x + style->PopupFrame.headerTextLeftPadding,
|
||||
y + style->PopupFrame.headerTextTopPadding,
|
||||
this->title.c_str(),
|
||||
nullptr);
|
||||
|
||||
// Sub title text 1
|
||||
nvgBeginPath(vg);
|
||||
nvgFillColor(vg, a(ctx->theme->descriptionColor));
|
||||
nvgFontFaceId(vg, ctx->fontStash->regular);
|
||||
nvgFontSize(vg, style->PopupFrame.subTitleFontSize);
|
||||
nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_TOP);
|
||||
nvgText(vg, x + style->PopupFrame.subTitleLeftPadding,
|
||||
y + style->PopupFrame.subTitleTopPadding,
|
||||
this->subTitleLeft.c_str(),
|
||||
nullptr);
|
||||
|
||||
float bounds[4];
|
||||
nvgTextBounds(vg, x, y, this->subTitleLeft.c_str(), nullptr, bounds);
|
||||
|
||||
// Sub title separator
|
||||
nvgFillColor(vg, a(ctx->theme->descriptionColor)); // we purposely don't apply opacity
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, x + style->PopupFrame.subTitleLeftPadding + (bounds[2] - bounds[0]) + style->PopupFrame.subTitleSpacing,
|
||||
y + style->PopupFrame.subTitleSeparatorTopPadding,
|
||||
1,
|
||||
style->PopupFrame.subTitleSeparatorHeight);
|
||||
nvgFill(vg);
|
||||
|
||||
// Sub title text 2
|
||||
nvgBeginPath(vg);
|
||||
nvgFillColor(vg, a(ctx->theme->descriptionColor));
|
||||
nvgFontFaceId(vg, ctx->fontStash->regular);
|
||||
nvgFontSize(vg, style->PopupFrame.subTitleFontSize);
|
||||
nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_TOP);
|
||||
nvgText(vg, x + style->PopupFrame.subTitleLeftPadding + (bounds[2] - bounds[0]) + (style->PopupFrame.subTitleSpacing * 2),
|
||||
y + style->PopupFrame.subTitleTopPadding,
|
||||
this->subTitleRight.c_str(),
|
||||
nullptr);
|
||||
|
||||
// Header
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, x + style->AppletFrame.separatorSpacing, y + style->AppletFrame.headerHeightPopup - 1, width - style->AppletFrame.separatorSpacing * 2, 1);
|
||||
nvgFill(vg);
|
||||
}
|
||||
|
||||
// Footer
|
||||
NVGcolor footerColor = a(ctx->theme->textColor);
|
||||
|
||||
if (this->slideIn)
|
||||
footerColor.a = 0.0f;
|
||||
else if (this->slideOut)
|
||||
footerColor.a = 1.0f;
|
||||
|
||||
nvgFillColor(vg, footerColor);
|
||||
|
||||
std::string* text = &this->footerText;
|
||||
|
||||
if (*text == "")
|
||||
text = Application::getCommonFooter();
|
||||
|
||||
nvgFontSize(vg, style->AppletFrame.footerTextSize);
|
||||
nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
|
||||
nvgBeginPath(vg);
|
||||
nvgText(vg, x + style->AppletFrame.separatorSpacing + style->AppletFrame.footerTextSpacing, y + height - style->AppletFrame.footerHeight / 2, text->c_str(), nullptr);
|
||||
|
||||
// Hint
|
||||
this->hint->frame(ctx);
|
||||
|
||||
// Icon
|
||||
if (this->icon)
|
||||
this->icon->frame(ctx);
|
||||
|
||||
// Separators
|
||||
nvgFillColor(vg, a(ctx->theme->separatorColor));
|
||||
|
||||
// Footer
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, x + style->AppletFrame.separatorSpacing, y + height - style->AppletFrame.footerHeight, width - style->AppletFrame.separatorSpacing * 2, 1);
|
||||
nvgFill(vg);
|
||||
|
||||
// Content view
|
||||
if (contentView)
|
||||
{
|
||||
float slideAlpha = 1.0f - this->contentView->alpha;
|
||||
|
||||
if ((this->slideIn && this->animation == ViewAnimation::SLIDE_LEFT) || (this->slideOut && this->animation == ViewAnimation::SLIDE_RIGHT))
|
||||
slideAlpha = 1.0f - slideAlpha;
|
||||
|
||||
int translation = (int)((float)style->AppletFrame.slideAnimation * slideAlpha);
|
||||
|
||||
if ((this->slideIn && this->animation == ViewAnimation::SLIDE_LEFT) || (this->slideOut && this->animation == ViewAnimation::SLIDE_RIGHT))
|
||||
translation -= style->AppletFrame.slideAnimation;
|
||||
|
||||
if (this->slideOut || this->slideIn)
|
||||
nvgTranslate(vg, -translation, 0);
|
||||
|
||||
contentView->frame(ctx);
|
||||
|
||||
if (this->slideOut || this->slideIn)
|
||||
nvgTranslate(vg, translation, 0);
|
||||
}
|
||||
}
|
||||
|
||||
View* AppletFrame::getDefaultFocus()
|
||||
{
|
||||
if (this->contentView)
|
||||
return this->contentView->getDefaultFocus();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AppletFrame::layout(NVGcontext* vg, Style* style, FontStash* stash)
|
||||
{
|
||||
// Icon
|
||||
if (this->icon)
|
||||
{
|
||||
if (this->headerStyle == HeaderStyle::REGULAR)
|
||||
{
|
||||
this->icon->setBoundaries(style->AppletFrame.imageLeftPadding, style->AppletFrame.imageTopPadding, style->AppletFrame.imageSize, style->AppletFrame.imageSize);
|
||||
this->icon->invalidate();
|
||||
}
|
||||
else if (this->headerStyle == HeaderStyle::POPUP)
|
||||
{
|
||||
this->icon->setBoundaries(style->PopupFrame.edgePadding + style->PopupFrame.imageLeftPadding, style->PopupFrame.imageTopPadding, style->PopupFrame.imageSize, style->PopupFrame.imageSize);
|
||||
this->icon->invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// Content
|
||||
if (this->contentView)
|
||||
{
|
||||
if (this->headerStyle == HeaderStyle::REGULAR)
|
||||
this->contentView->setBoundaries(this->x + leftPadding, this->y + style->AppletFrame.headerHeightRegular, this->width - this->leftPadding - this->rightPadding, this->height - style->AppletFrame.footerHeight - style->AppletFrame.headerHeightRegular);
|
||||
else if (this->headerStyle == HeaderStyle::POPUP)
|
||||
this->contentView->setBoundaries(this->x + leftPadding, this->y + style->AppletFrame.headerHeightPopup, this->width - this->leftPadding - this->rightPadding, this->height - style->AppletFrame.footerHeight - style->AppletFrame.headerHeightPopup);
|
||||
|
||||
this->contentView->invalidate();
|
||||
}
|
||||
|
||||
// Hint
|
||||
// TODO: convert the bottom-left footer into a Label to get its width and avoid clipping with the hint
|
||||
unsigned hintWidth = this->width - style->AppletFrame.separatorSpacing * 2 - style->AppletFrame.footerTextSpacing * 2;
|
||||
|
||||
this->hint->setBoundaries(
|
||||
this->x + this->width - hintWidth - style->AppletFrame.separatorSpacing - style->AppletFrame.footerTextSpacing,
|
||||
this->y + this->height - style->AppletFrame.footerHeight,
|
||||
hintWidth,
|
||||
style->AppletFrame.footerHeight);
|
||||
this->hint->invalidate();
|
||||
}
|
||||
|
||||
void AppletFrame::setContentView(View* view)
|
||||
{
|
||||
this->contentView = view;
|
||||
|
||||
if (this->contentView)
|
||||
{
|
||||
this->contentView->setParent(this);
|
||||
this->contentView->willAppear();
|
||||
}
|
||||
|
||||
this->invalidate();
|
||||
}
|
||||
|
||||
bool AppletFrame::hasContentView()
|
||||
{
|
||||
return this->contentView;
|
||||
}
|
||||
|
||||
void AppletFrame::setTitle(std::string title)
|
||||
{
|
||||
this->title = title;
|
||||
}
|
||||
|
||||
void AppletFrame::setFooterText(std::string footerText)
|
||||
{
|
||||
this->footerText = footerText;
|
||||
}
|
||||
|
||||
void AppletFrame::setSubtitle(std::string left, std::string right)
|
||||
{
|
||||
this->subTitleLeft = left;
|
||||
this->subTitleRight = right;
|
||||
}
|
||||
|
||||
void AppletFrame::setIcon(unsigned char* buffer, size_t bufferSize)
|
||||
{
|
||||
if (!this->icon)
|
||||
{
|
||||
Image* icon = new Image(buffer, bufferSize);
|
||||
icon->setScaleType(ImageScaleType::SCALE);
|
||||
icon->setParent(this);
|
||||
|
||||
this->icon = icon;
|
||||
}
|
||||
else if (Image* icon = dynamic_cast<Image*>(this->icon))
|
||||
{
|
||||
icon->setImage(buffer, bufferSize);
|
||||
}
|
||||
|
||||
this->icon->invalidate();
|
||||
}
|
||||
|
||||
void AppletFrame::setIcon(std::string imagePath)
|
||||
{
|
||||
if (!this->icon)
|
||||
{
|
||||
Image* icon = new Image(imagePath);
|
||||
icon->setScaleType(ImageScaleType::SCALE);
|
||||
icon->setParent(this);
|
||||
|
||||
this->icon = icon;
|
||||
}
|
||||
else if (Image* icon = dynamic_cast<Image*>(this->icon))
|
||||
{
|
||||
icon->setImage(imagePath);
|
||||
}
|
||||
|
||||
this->icon->invalidate();
|
||||
}
|
||||
|
||||
void AppletFrame::setIcon(View* view)
|
||||
{
|
||||
if (this->icon)
|
||||
delete this->icon;
|
||||
|
||||
if (view != nullptr)
|
||||
view->setParent(this);
|
||||
|
||||
this->icon = view;
|
||||
}
|
||||
|
||||
void AppletFrame::setHeaderStyle(HeaderStyle headerStyle)
|
||||
{
|
||||
this->headerStyle = headerStyle;
|
||||
|
||||
this->invalidate();
|
||||
}
|
||||
|
||||
AppletFrame::~AppletFrame()
|
||||
{
|
||||
if (this->contentView)
|
||||
{
|
||||
this->contentView->willDisappear(true);
|
||||
delete this->contentView;
|
||||
}
|
||||
|
||||
if (this->icon)
|
||||
delete this->icon;
|
||||
|
||||
delete this->hint;
|
||||
}
|
||||
|
||||
void AppletFrame::willAppear(bool resetState)
|
||||
{
|
||||
if (this->icon)
|
||||
this->icon->willAppear(resetState);
|
||||
|
||||
if (this->contentView)
|
||||
this->contentView->willAppear(resetState);
|
||||
|
||||
this->hint->willAppear(resetState);
|
||||
}
|
||||
|
||||
void AppletFrame::willDisappear(bool resetState)
|
||||
{
|
||||
if (this->icon)
|
||||
this->icon->willDisappear(resetState);
|
||||
|
||||
if (this->contentView)
|
||||
this->contentView->willDisappear(resetState);
|
||||
|
||||
this->hint->willDisappear(resetState);
|
||||
}
|
||||
|
||||
void AppletFrame::show(std::function<void(void)> cb, bool animated, ViewAnimation animation)
|
||||
{
|
||||
this->animation = animation;
|
||||
|
||||
if (animated && (animation == ViewAnimation::SLIDE_LEFT || animation == ViewAnimation::SLIDE_RIGHT) && this->contentView)
|
||||
{
|
||||
this->slideIn = true;
|
||||
|
||||
this->contentView->show([this]() {
|
||||
this->slideIn = false;
|
||||
},
|
||||
true, animation);
|
||||
}
|
||||
else if (this->contentView && this->contentView->isHidden())
|
||||
{
|
||||
this->contentView->show([]() {}, animated, animation);
|
||||
}
|
||||
|
||||
View::show(cb, animated, animation);
|
||||
}
|
||||
|
||||
void AppletFrame::hide(std::function<void(void)> cb, bool animated, ViewAnimation animation)
|
||||
{
|
||||
this->animation = animation;
|
||||
|
||||
if (animated && (animation == ViewAnimation::SLIDE_LEFT || animation == ViewAnimation::SLIDE_RIGHT) && this->contentView)
|
||||
{
|
||||
this->slideOut = true;
|
||||
|
||||
this->contentView->hide([this, cb]() {
|
||||
this->slideOut = false;
|
||||
},
|
||||
true, animation);
|
||||
}
|
||||
else if (this->contentView && !this->contentView->isHidden())
|
||||
{
|
||||
this->contentView->hide([]() {}, animated, animation);
|
||||
}
|
||||
|
||||
View::hide(cb, animated, animation);
|
||||
}
|
||||
|
||||
bool AppletFrame::onCancel()
|
||||
{
|
||||
/*
|
||||
* TODO: this assumes AppletFrames are used as "activities" in the app, which may be wrong
|
||||
* so we should instead change the view stack to an "activity" stack and have them popped when
|
||||
* the user presses B on the root view of an "activity"
|
||||
*/
|
||||
Application::popView();
|
||||
return true;
|
||||
}
|
||||
|
||||
void AppletFrame::onWindowSizeChanged()
|
||||
{
|
||||
if (this->contentView)
|
||||
this->contentView->onWindowSizeChanged();
|
||||
|
||||
if (this->icon)
|
||||
this->icon->onWindowSizeChanged();
|
||||
|
||||
if (this->hint)
|
||||
this->hint->onWindowSizeChanged();
|
||||
}
|
||||
|
||||
} // namespace brls
|
||||
991
lib/borealis/library/lib/application.cpp
Normal file
991
lib/borealis/library/lib/application.cpp
Normal file
@@ -0,0 +1,991 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019-2020 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
Copyright (C) 2020 WerWolv
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <borealis.hpp>
|
||||
#include <string>
|
||||
|
||||
#define GLFW_INCLUDE_NONE
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <glad.h>
|
||||
|
||||
#define GLM_FORCE_PURE
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include <nanovg.h>
|
||||
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <glm/gtx/rotate_vector.hpp>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <glm/vec3.hpp>
|
||||
#include <glm/vec4.hpp>
|
||||
#define NANOVG_GL3_IMPLEMENTATION
|
||||
#include <nanovg_gl.h>
|
||||
|
||||
#ifdef __SWITCH__
|
||||
#include <switch.h>
|
||||
#endif
|
||||
|
||||
#include <chrono>
|
||||
#include <set>
|
||||
#include <thread>
|
||||
|
||||
// Constants used for scaling as well as
|
||||
// creating a window of the right size on PC
|
||||
constexpr uint32_t WINDOW_WIDTH = 1280;
|
||||
constexpr uint32_t WINDOW_HEIGHT = 720;
|
||||
|
||||
#define DEFAULT_FPS 60
|
||||
#define BUTTON_REPEAT_DELAY 15
|
||||
#define BUTTON_REPEAT_CADENCY 5
|
||||
|
||||
// glfw code from the glfw hybrid app by fincs
|
||||
// https://github.com/fincs/hybrid_app
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// TODO: Use this instead of a glViewport each frame
|
||||
static void windowFramebufferSizeCallback(GLFWwindow* window, int width, int height)
|
||||
{
|
||||
if (!width || !height)
|
||||
return;
|
||||
|
||||
glViewport(0, 0, width, height);
|
||||
Application::windowScale = (float)width / (float)WINDOW_WIDTH;
|
||||
|
||||
float contentHeight = ((float)height / (Application::windowScale * (float)WINDOW_HEIGHT)) * (float)WINDOW_HEIGHT;
|
||||
|
||||
Application::contentWidth = WINDOW_WIDTH;
|
||||
Application::contentHeight = (unsigned)roundf(contentHeight);
|
||||
|
||||
Application::resizeNotificationManager();
|
||||
|
||||
Logger::info("Window size changed to %dx%d", width, height);
|
||||
Logger::info("New scale factor is %f", Application::windowScale);
|
||||
}
|
||||
|
||||
static void joystickCallback(int jid, int event)
|
||||
{
|
||||
if (event == GLFW_CONNECTED)
|
||||
{
|
||||
Logger::info("Joystick %d connected", jid);
|
||||
if (glfwJoystickIsGamepad(jid))
|
||||
Logger::info("Joystick %d is gamepad: \"%s\"", jid, glfwGetGamepadName(jid));
|
||||
}
|
||||
else if (event == GLFW_DISCONNECTED)
|
||||
Logger::info("Joystick %d disconnected", jid);
|
||||
}
|
||||
|
||||
static void errorCallback(int errorCode, const char* description)
|
||||
{
|
||||
Logger::error("[GLFW:%d] %s", errorCode, description);
|
||||
}
|
||||
|
||||
static void windowKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
if (action == GLFW_PRESS)
|
||||
{
|
||||
// Check for toggle-fullscreen combo
|
||||
if (key == GLFW_KEY_ENTER && mods == GLFW_MOD_ALT)
|
||||
{
|
||||
static int saved_x, saved_y, saved_width, saved_height;
|
||||
|
||||
if (!glfwGetWindowMonitor(window))
|
||||
{
|
||||
// Back up window position/size
|
||||
glfwGetWindowPos(window, &saved_x, &saved_y);
|
||||
glfwGetWindowSize(window, &saved_width, &saved_height);
|
||||
|
||||
// Switch to fullscreen mode
|
||||
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
|
||||
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
|
||||
glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Switch back to windowed mode
|
||||
glfwSetWindowMonitor(window, nullptr, saved_x, saved_y, saved_width, saved_height, GLFW_DONT_CARE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Application::init(std::string title)
|
||||
{
|
||||
return Application::init(title, Style::horizon(), Theme::horizon());
|
||||
}
|
||||
|
||||
bool Application::init(std::string title, Style style, Theme theme)
|
||||
{
|
||||
// Init rng
|
||||
std::srand(std::time(nullptr));
|
||||
|
||||
// Init managers
|
||||
Application::taskManager = new TaskManager();
|
||||
Application::notificationManager = new NotificationManager();
|
||||
|
||||
// Init static variables
|
||||
Application::currentStyle = style;
|
||||
Application::currentFocus = nullptr;
|
||||
Application::oldGamepad = {};
|
||||
Application::gamepad = {};
|
||||
Application::title = title;
|
||||
|
||||
// Init theme to defaults
|
||||
Application::setTheme(theme);
|
||||
|
||||
// Init glfw
|
||||
glfwSetErrorCallback(errorCallback);
|
||||
glfwInitHint(GLFW_JOYSTICK_HAT_BUTTONS, GLFW_FALSE);
|
||||
if (!glfwInit())
|
||||
{
|
||||
Logger::error("Failed to initialize glfw");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create window
|
||||
#ifdef __APPLE__
|
||||
// Explicitly ask for a 3.2 context on OS X
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
// Force scaling off to keep desired framebuffer size
|
||||
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE);
|
||||
#else
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
#endif
|
||||
|
||||
Application::window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, title.c_str(), nullptr, nullptr);
|
||||
if (!window)
|
||||
{
|
||||
Logger::error("glfw: failed to create window\n");
|
||||
glfwTerminate();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Configure window
|
||||
glfwSetInputMode(window, GLFW_STICKY_KEYS, GLFW_TRUE);
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSetFramebufferSizeCallback(window, windowFramebufferSizeCallback);
|
||||
glfwSetKeyCallback(window, windowKeyCallback);
|
||||
glfwSetJoystickCallback(joystickCallback);
|
||||
|
||||
// Load OpenGL routines using glad
|
||||
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
|
||||
glfwSwapInterval(1);
|
||||
|
||||
Logger::info("GL Vendor: %s", glGetString(GL_VENDOR));
|
||||
Logger::info("GL Renderer: %s", glGetString(GL_RENDERER));
|
||||
Logger::info("GL Version: %s", glGetString(GL_VERSION));
|
||||
|
||||
if (glfwJoystickIsGamepad(GLFW_JOYSTICK_1))
|
||||
{
|
||||
GLFWgamepadstate state;
|
||||
Logger::info("Gamepad detected: %s", glfwGetGamepadName(GLFW_JOYSTICK_1));
|
||||
glfwGetGamepadState(GLFW_JOYSTICK_1, &state);
|
||||
}
|
||||
|
||||
// Initialize the scene
|
||||
Application::vg = nvgCreateGL3(NVG_STENCIL_STROKES | NVG_ANTIALIAS);
|
||||
if (!vg)
|
||||
{
|
||||
Logger::error("Unable to init nanovg");
|
||||
glfwTerminate();
|
||||
return false;
|
||||
}
|
||||
|
||||
windowFramebufferSizeCallback(window, WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
glfwSetTime(0.0);
|
||||
|
||||
// Load fonts
|
||||
#ifdef __SWITCH__
|
||||
{
|
||||
PlFontData font;
|
||||
|
||||
// Standard font
|
||||
Result rc = plGetSharedFontByType(&font, PlSharedFontType_Standard);
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
Logger::info("Using Switch shared font");
|
||||
Application::fontStash.regular = Application::loadFontFromMemory("regular", font.address, font.size, false);
|
||||
}
|
||||
|
||||
// Korean font
|
||||
rc = plGetSharedFontByType(&font, PlSharedFontType_KO);
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
Logger::info("Adding Switch shared Korean font");
|
||||
Application::fontStash.korean = Application::loadFontFromMemory("korean", font.address, font.size, false);
|
||||
nvgAddFallbackFontId(Application::vg, Application::fontStash.regular, Application::fontStash.korean);
|
||||
}
|
||||
|
||||
// Extented font
|
||||
rc = plGetSharedFontByType(&font, PlSharedFontType_NintendoExt);
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
Logger::info("Using Switch shared symbols font");
|
||||
Application::fontStash.sharedSymbols = Application::loadFontFromMemory("symbols", font.address, font.size, false);
|
||||
}
|
||||
}
|
||||
#else
|
||||
// Use illegal font if available
|
||||
if (access(BOREALIS_ASSET("Illegal-Font.ttf"), F_OK) != -1)
|
||||
Application::fontStash.regular = Application::loadFont("regular", BOREALIS_ASSET("Illegal-Font.ttf"));
|
||||
else
|
||||
Application::fontStash.regular = Application::loadFont("regular", BOREALIS_ASSET("inter/Inter-Switch.ttf"));
|
||||
|
||||
if (access(BOREALIS_ASSET("Wingdings.ttf"), F_OK) != -1)
|
||||
Application::fontStash.sharedSymbols = Application::loadFont("sharedSymbols", BOREALIS_ASSET("Wingdings.ttf"));
|
||||
#endif
|
||||
|
||||
// Material font
|
||||
if (access(BOREALIS_ASSET("material/MaterialIcons-Regular.ttf"), F_OK) != -1)
|
||||
Application::fontStash.material = Application::loadFont("material", BOREALIS_ASSET("material/MaterialIcons-Regular.ttf"));
|
||||
|
||||
// Set symbols font as fallback
|
||||
if (Application::fontStash.sharedSymbols)
|
||||
{
|
||||
Logger::info("Using shared symbols font");
|
||||
nvgAddFallbackFontId(Application::vg, Application::fontStash.regular, Application::fontStash.sharedSymbols);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error("Shared symbols font not found");
|
||||
}
|
||||
|
||||
// Set Material as fallback
|
||||
if (Application::fontStash.material)
|
||||
{
|
||||
Logger::info("Using Material font");
|
||||
nvgAddFallbackFontId(Application::vg, Application::fontStash.regular, Application::fontStash.material);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error("Material font not found");
|
||||
}
|
||||
|
||||
// Load theme
|
||||
#ifdef __SWITCH__
|
||||
ColorSetId nxTheme;
|
||||
setsysGetColorSetId(&nxTheme);
|
||||
|
||||
if (nxTheme == ColorSetId_Dark)
|
||||
Application::currentThemeVariant = ThemeVariant_DARK;
|
||||
else
|
||||
Application::currentThemeVariant = ThemeVariant_LIGHT;
|
||||
#else
|
||||
char* themeEnv = getenv("BOREALIS_THEME");
|
||||
if (themeEnv != nullptr && !strcasecmp(themeEnv, "DARK"))
|
||||
Application::currentThemeVariant = ThemeVariant_DARK;
|
||||
else
|
||||
Application::currentThemeVariant = ThemeVariant_LIGHT;
|
||||
#endif
|
||||
|
||||
// Init window size
|
||||
GLint viewport[4];
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
|
||||
Application::windowWidth = viewport[2];
|
||||
Application::windowHeight = viewport[3];
|
||||
|
||||
// Init animations engine
|
||||
menu_animation_init();
|
||||
|
||||
// Default FPS cap
|
||||
Application::setMaximumFPS(DEFAULT_FPS);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Application::mainLoop()
|
||||
{
|
||||
// Frame start
|
||||
retro_time_t frameStart = 0;
|
||||
if (Application::frameTime > 0.0f)
|
||||
frameStart = cpu_features_get_time_usec();
|
||||
|
||||
// glfw events
|
||||
bool is_active;
|
||||
do
|
||||
{
|
||||
is_active = !glfwGetWindowAttrib(Application::window, GLFW_ICONIFIED);
|
||||
if (is_active)
|
||||
glfwPollEvents();
|
||||
else
|
||||
glfwWaitEvents();
|
||||
|
||||
if (glfwWindowShouldClose(Application::window))
|
||||
{
|
||||
Application::exit();
|
||||
return false;
|
||||
}
|
||||
} while (!is_active);
|
||||
|
||||
// libnx applet main loop
|
||||
#ifdef __SWITCH__
|
||||
if (!appletMainLoop())
|
||||
{
|
||||
Application::exit();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Gamepad
|
||||
if (!glfwGetGamepadState(GLFW_JOYSTICK_1, &Application::gamepad))
|
||||
{
|
||||
// Keyboard -> DPAD Mapping
|
||||
Application::gamepad.buttons[GLFW_GAMEPAD_BUTTON_DPAD_LEFT] = glfwGetKey(window, GLFW_KEY_LEFT);
|
||||
Application::gamepad.buttons[GLFW_GAMEPAD_BUTTON_DPAD_RIGHT] = glfwGetKey(window, GLFW_KEY_RIGHT);
|
||||
Application::gamepad.buttons[GLFW_GAMEPAD_BUTTON_DPAD_UP] = glfwGetKey(window, GLFW_KEY_UP);
|
||||
Application::gamepad.buttons[GLFW_GAMEPAD_BUTTON_DPAD_DOWN] = glfwGetKey(window, GLFW_KEY_DOWN);
|
||||
Application::gamepad.buttons[GLFW_GAMEPAD_BUTTON_START] = glfwGetKey(window, GLFW_KEY_ESCAPE);
|
||||
Application::gamepad.buttons[GLFW_GAMEPAD_BUTTON_BACK] = glfwGetKey(window, GLFW_KEY_F1);
|
||||
Application::gamepad.buttons[GLFW_GAMEPAD_BUTTON_A] = glfwGetKey(window, GLFW_KEY_ENTER);
|
||||
Application::gamepad.buttons[GLFW_GAMEPAD_BUTTON_B] = glfwGetKey(window, GLFW_KEY_BACKSPACE);
|
||||
Application::gamepad.buttons[GLFW_GAMEPAD_BUTTON_LEFT_BUMPER] = glfwGetKey(window, GLFW_KEY_L);
|
||||
Application::gamepad.buttons[GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER] = glfwGetKey(window, GLFW_KEY_R);
|
||||
}
|
||||
|
||||
// Trigger gamepad events
|
||||
// TODO: Translate axis events to dpad events here
|
||||
|
||||
bool anyButtonPressed = false;
|
||||
bool repeating = false;
|
||||
static retro_time_t buttonPressTime = 0;
|
||||
static int repeatingButtonTimer = 0;
|
||||
|
||||
for (int i = GLFW_GAMEPAD_BUTTON_A; i <= GLFW_GAMEPAD_BUTTON_LAST; i++)
|
||||
{
|
||||
if (Application::gamepad.buttons[i] == GLFW_PRESS)
|
||||
{
|
||||
anyButtonPressed = true;
|
||||
repeating = (repeatingButtonTimer > BUTTON_REPEAT_DELAY && repeatingButtonTimer % BUTTON_REPEAT_CADENCY == 0);
|
||||
|
||||
if (Application::oldGamepad.buttons[i] != GLFW_PRESS || repeating)
|
||||
Application::onGamepadButtonPressed(i, repeating);
|
||||
}
|
||||
|
||||
if (Application::gamepad.buttons[i] != Application::oldGamepad.buttons[i])
|
||||
buttonPressTime = repeatingButtonTimer = 0;
|
||||
}
|
||||
|
||||
if (anyButtonPressed && cpu_features_get_time_usec() - buttonPressTime > 1000)
|
||||
{
|
||||
buttonPressTime = cpu_features_get_time_usec();
|
||||
repeatingButtonTimer++; // Increased once every ~1ms
|
||||
}
|
||||
|
||||
Application::oldGamepad = Application::gamepad;
|
||||
|
||||
// Handle window size changes
|
||||
GLint viewport[4];
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
|
||||
unsigned newWidth = viewport[2];
|
||||
unsigned newHeight = viewport[3];
|
||||
|
||||
if (Application::windowWidth != newWidth || Application::windowHeight != newHeight)
|
||||
{
|
||||
Application::windowWidth = newWidth;
|
||||
Application::windowHeight = newHeight;
|
||||
Application::onWindowSizeChanged();
|
||||
}
|
||||
|
||||
// Animations
|
||||
menu_animation_update();
|
||||
|
||||
// Tasks
|
||||
Application::taskManager->frame();
|
||||
|
||||
// Render
|
||||
Application::frame();
|
||||
glfwSwapBuffers(window);
|
||||
|
||||
// Sleep if necessary
|
||||
if (Application::frameTime > 0.0f)
|
||||
{
|
||||
retro_time_t currentFrameTime = cpu_features_get_time_usec() - frameStart;
|
||||
retro_time_t frameTime = (retro_time_t)(Application::frameTime * 1000);
|
||||
|
||||
if (frameTime > currentFrameTime)
|
||||
{
|
||||
retro_time_t toSleep = frameTime - currentFrameTime;
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(toSleep));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Application::quit()
|
||||
{
|
||||
glfwSetWindowShouldClose(window, GLFW_TRUE);
|
||||
}
|
||||
|
||||
void Application::navigate(FocusDirection direction)
|
||||
{
|
||||
View* currentFocus = Application::currentFocus;
|
||||
|
||||
// Do nothing if there is no current focus or if it doesn't have a parent
|
||||
// (in which case there is nothing to traverse)
|
||||
if (!currentFocus || !currentFocus->hasParent())
|
||||
return;
|
||||
|
||||
// Get next view to focus by traversing the views tree upwards
|
||||
View* nextFocus = currentFocus->getParent()->getNextFocus(direction, currentFocus->getParentUserData());
|
||||
|
||||
while (!nextFocus) // stop when we find a view to focus
|
||||
{
|
||||
if (!currentFocus->hasParent() || !currentFocus->getParent()->hasParent()) // stop when we reach the root of the tree
|
||||
break;
|
||||
|
||||
currentFocus = currentFocus->getParent();
|
||||
nextFocus = currentFocus->getParent()->getNextFocus(direction, currentFocus->getParentUserData());
|
||||
}
|
||||
|
||||
// No view to focus at the end of the traversal: wiggle and return
|
||||
if (!nextFocus)
|
||||
{
|
||||
Application::currentFocus->shakeHighlight(direction);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise give it focus
|
||||
Application::giveFocus(nextFocus);
|
||||
}
|
||||
|
||||
void Application::onGamepadButtonPressed(char button, bool repeating)
|
||||
{
|
||||
if (Application::blockInputsTokens != 0)
|
||||
return;
|
||||
|
||||
if (repeating && Application::repetitionOldFocus == Application::currentFocus)
|
||||
return;
|
||||
|
||||
Application::repetitionOldFocus = Application::currentFocus;
|
||||
|
||||
// Actions
|
||||
if (Application::handleAction(button))
|
||||
return;
|
||||
|
||||
// Navigation
|
||||
// Only navigate if the button hasn't been consumed by an action
|
||||
// (allows overriding DPAD buttons using actions)
|
||||
switch (button)
|
||||
{
|
||||
case GLFW_GAMEPAD_BUTTON_DPAD_DOWN:
|
||||
Application::navigate(FocusDirection::DOWN);
|
||||
break;
|
||||
case GLFW_GAMEPAD_BUTTON_DPAD_UP:
|
||||
Application::navigate(FocusDirection::UP);
|
||||
break;
|
||||
case GLFW_GAMEPAD_BUTTON_DPAD_LEFT:
|
||||
Application::navigate(FocusDirection::LEFT);
|
||||
break;
|
||||
case GLFW_GAMEPAD_BUTTON_DPAD_RIGHT:
|
||||
Application::navigate(FocusDirection::RIGHT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
View* Application::getCurrentFocus()
|
||||
{
|
||||
return Application::currentFocus;
|
||||
}
|
||||
|
||||
bool Application::handleAction(char button)
|
||||
{
|
||||
View* hintParent = Application::currentFocus;
|
||||
std::set<Key> consumedKeys;
|
||||
|
||||
while (hintParent != nullptr)
|
||||
{
|
||||
for (auto& action : hintParent->getActions())
|
||||
{
|
||||
if (action.key != static_cast<Key>(button))
|
||||
continue;
|
||||
|
||||
if (consumedKeys.find(action.key) != consumedKeys.end())
|
||||
continue;
|
||||
|
||||
if (action.available)
|
||||
if (action.actionListener())
|
||||
consumedKeys.insert(action.key);
|
||||
}
|
||||
|
||||
hintParent = hintParent->getParent();
|
||||
}
|
||||
|
||||
return !consumedKeys.empty();
|
||||
}
|
||||
|
||||
void Application::frame()
|
||||
{
|
||||
// Frame context
|
||||
FrameContext frameContext = FrameContext();
|
||||
|
||||
frameContext.pixelRatio = (float)Application::windowWidth / (float)Application::windowHeight;
|
||||
frameContext.vg = Application::vg;
|
||||
frameContext.fontStash = &Application::fontStash;
|
||||
frameContext.theme = Application::getThemeValues();
|
||||
|
||||
nvgBeginFrame(Application::vg, Application::windowWidth, Application::windowHeight, frameContext.pixelRatio);
|
||||
nvgScale(Application::vg, Application::windowScale, Application::windowScale);
|
||||
|
||||
// GL Clear
|
||||
glClearColor(
|
||||
frameContext.theme->backgroundColor[0],
|
||||
frameContext.theme->backgroundColor[1],
|
||||
frameContext.theme->backgroundColor[2],
|
||||
1.0f);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
std::vector<View*> viewsToDraw;
|
||||
|
||||
// Draw all views in the stack
|
||||
// until we find one that's not translucent
|
||||
for (size_t i = 0; i < Application::viewStack.size(); i++)
|
||||
{
|
||||
View* view = Application::viewStack[Application::viewStack.size() - 1 - i];
|
||||
viewsToDraw.push_back(view);
|
||||
|
||||
if (!view->isTranslucent())
|
||||
break;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < viewsToDraw.size(); i++)
|
||||
{
|
||||
View* view = viewsToDraw[viewsToDraw.size() - 1 - i];
|
||||
view->frame(&frameContext);
|
||||
}
|
||||
|
||||
// Framerate counter
|
||||
if (Application::framerateCounter)
|
||||
Application::framerateCounter->frame(&frameContext);
|
||||
|
||||
// Notifications
|
||||
Application::notificationManager->frame(&frameContext);
|
||||
|
||||
// End frame
|
||||
nvgResetTransform(Application::vg); // scale
|
||||
nvgEndFrame(Application::vg);
|
||||
}
|
||||
|
||||
void Application::exit()
|
||||
{
|
||||
Application::clear();
|
||||
|
||||
if (Application::vg)
|
||||
nvgDeleteGL3(Application::vg);
|
||||
|
||||
glfwTerminate();
|
||||
|
||||
menu_animation_free();
|
||||
|
||||
if (Application::framerateCounter)
|
||||
delete Application::framerateCounter;
|
||||
|
||||
delete Application::taskManager;
|
||||
delete Application::notificationManager;
|
||||
}
|
||||
|
||||
void Application::setDisplayFramerate(bool enabled)
|
||||
{
|
||||
if (!Application::framerateCounter && enabled)
|
||||
{
|
||||
Logger::info("Enabling framerate counter");
|
||||
Application::framerateCounter = new FramerateCounter();
|
||||
Application::resizeFramerateCounter();
|
||||
}
|
||||
else if (Application::framerateCounter && !enabled)
|
||||
{
|
||||
Logger::info("Disabling framerate counter");
|
||||
delete Application::framerateCounter;
|
||||
Application::framerateCounter = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Application::toggleFramerateDisplay()
|
||||
{
|
||||
Application::setDisplayFramerate(!Application::framerateCounter);
|
||||
}
|
||||
|
||||
void Application::resizeFramerateCounter()
|
||||
{
|
||||
if (!Application::framerateCounter)
|
||||
return;
|
||||
|
||||
Style* style = Application::getStyle();
|
||||
unsigned framerateCounterWidth = style->FramerateCounter.width;
|
||||
unsigned width = WINDOW_WIDTH;
|
||||
|
||||
Application::framerateCounter->setBoundaries(
|
||||
width - framerateCounterWidth,
|
||||
0,
|
||||
framerateCounterWidth,
|
||||
style->FramerateCounter.height);
|
||||
Application::framerateCounter->invalidate();
|
||||
}
|
||||
|
||||
void Application::resizeNotificationManager()
|
||||
{
|
||||
Application::notificationManager->setBoundaries(0, 0, Application::contentWidth, Application::contentHeight);
|
||||
Application::notificationManager->invalidate();
|
||||
}
|
||||
|
||||
void Application::notify(std::string text)
|
||||
{
|
||||
Application::notificationManager->notify(text);
|
||||
}
|
||||
|
||||
NotificationManager* Application::getNotificationManager()
|
||||
{
|
||||
return Application::notificationManager;
|
||||
}
|
||||
|
||||
void Application::giveFocus(View* view)
|
||||
{
|
||||
View* oldFocus = Application::currentFocus;
|
||||
View* newFocus = view ? view->getDefaultFocus() : nullptr;
|
||||
|
||||
if (oldFocus != newFocus)
|
||||
{
|
||||
if (oldFocus)
|
||||
oldFocus->onFocusLost();
|
||||
|
||||
Application::currentFocus = newFocus;
|
||||
Application::globalFocusChangeEvent.fire(newFocus);
|
||||
|
||||
if (newFocus)
|
||||
{
|
||||
newFocus->onFocusGained();
|
||||
Logger::debug("Giving focus to %s", newFocus->describe().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Application::popView(ViewAnimation animation, std::function<void(void)> cb)
|
||||
{
|
||||
if (Application::viewStack.size() <= 1) // never pop the root view
|
||||
return;
|
||||
|
||||
Application::blockInputs();
|
||||
|
||||
View* last = Application::viewStack[Application::viewStack.size() - 1];
|
||||
last->willDisappear(true);
|
||||
|
||||
last->setForceTranslucent(true);
|
||||
|
||||
bool wait = animation == ViewAnimation::FADE; // wait for the new view animation to be done before showing the old one?
|
||||
|
||||
// Hide animation (and show previous view, if any)
|
||||
last->hide([last, animation, wait, cb]() {
|
||||
last->setForceTranslucent(false);
|
||||
Application::viewStack.pop_back();
|
||||
delete last;
|
||||
|
||||
// Animate the old view once the new one
|
||||
// has ended its animation
|
||||
if (Application::viewStack.size() > 0 && wait)
|
||||
{
|
||||
View* newLast = Application::viewStack[Application::viewStack.size() - 1];
|
||||
|
||||
if (newLast->isHidden())
|
||||
{
|
||||
newLast->willAppear(false);
|
||||
newLast->show(cb, true, animation);
|
||||
}
|
||||
else
|
||||
{
|
||||
cb();
|
||||
}
|
||||
}
|
||||
|
||||
Application::unblockInputs();
|
||||
},
|
||||
true, animation);
|
||||
|
||||
// Animate the old view immediately
|
||||
if (!wait && Application::viewStack.size() > 1)
|
||||
{
|
||||
View* toShow = Application::viewStack[Application::viewStack.size() - 2];
|
||||
toShow->willAppear(false);
|
||||
toShow->show(cb, true, animation);
|
||||
}
|
||||
|
||||
// Focus
|
||||
if (Application::focusStack.size() > 0)
|
||||
{
|
||||
View* newFocus = Application::focusStack[Application::focusStack.size() - 1];
|
||||
|
||||
Logger::debug("Giving focus to %s, and removing it from the focus stack", newFocus->describe().c_str());
|
||||
|
||||
Application::giveFocus(newFocus);
|
||||
Application::focusStack.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::pushView(View* view, ViewAnimation animation)
|
||||
{
|
||||
Application::blockInputs();
|
||||
|
||||
// Call hide() on the previous view in the stack if no
|
||||
// views are translucent, then call show() once the animation ends
|
||||
View* last = nullptr;
|
||||
if (Application::viewStack.size() > 0)
|
||||
last = Application::viewStack[Application::viewStack.size() - 1];
|
||||
|
||||
bool fadeOut = last && !last->isTranslucent() && !view->isTranslucent(); // play the fade out animation?
|
||||
bool wait = animation == ViewAnimation::FADE; // wait for the old view animation to be done before showing the new one?
|
||||
|
||||
view->registerAction("Exit", Key::PLUS, [] { Application::quit(); return true; });
|
||||
view->registerAction(
|
||||
"FPS", Key::MINUS, [] { Application::toggleFramerateDisplay(); return true; }, true);
|
||||
|
||||
// Fade out animation
|
||||
if (fadeOut)
|
||||
{
|
||||
view->setForceTranslucent(true); // set the new view translucent until the fade out animation is done playing
|
||||
|
||||
// Animate the new view directly
|
||||
if (!wait)
|
||||
{
|
||||
view->show([]() {
|
||||
Application::unblockInputs();
|
||||
},
|
||||
true, animation);
|
||||
}
|
||||
|
||||
last->hide([animation, wait]() {
|
||||
View* newLast = Application::viewStack[Application::viewStack.size() - 1];
|
||||
newLast->setForceTranslucent(false);
|
||||
|
||||
// Animate the new view once the old one
|
||||
// has ended its animation
|
||||
if (wait)
|
||||
newLast->show([]() { Application::unblockInputs(); }, true, animation);
|
||||
},
|
||||
true, animation);
|
||||
}
|
||||
|
||||
view->setBoundaries(0, 0, Application::contentWidth, Application::contentHeight);
|
||||
|
||||
if (!fadeOut)
|
||||
view->show([]() { Application::unblockInputs(); }, true, animation);
|
||||
else
|
||||
view->alpha = 0.0f;
|
||||
|
||||
// Focus
|
||||
if (Application::viewStack.size() > 0)
|
||||
{
|
||||
Logger::debug("Pushing %s to the focus stack", Application::currentFocus->describe().c_str());
|
||||
Application::focusStack.push_back(Application::currentFocus);
|
||||
}
|
||||
|
||||
// Layout and prepare view
|
||||
view->invalidate(true);
|
||||
view->willAppear(true);
|
||||
Application::giveFocus(view->getDefaultFocus());
|
||||
|
||||
// And push it
|
||||
Application::viewStack.push_back(view);
|
||||
}
|
||||
|
||||
void Application::onWindowSizeChanged()
|
||||
{
|
||||
Logger::debug("Layout triggered");
|
||||
|
||||
for (View* view : Application::viewStack)
|
||||
{
|
||||
view->setBoundaries(0, 0, Application::contentWidth, Application::contentHeight);
|
||||
view->invalidate();
|
||||
|
||||
view->onWindowSizeChanged();
|
||||
}
|
||||
|
||||
Application::resizeNotificationManager();
|
||||
Application::resizeFramerateCounter();
|
||||
}
|
||||
|
||||
void Application::clear()
|
||||
{
|
||||
for (View* view : Application::viewStack)
|
||||
{
|
||||
view->willDisappear(true);
|
||||
delete view;
|
||||
}
|
||||
|
||||
Application::viewStack.clear();
|
||||
}
|
||||
|
||||
Style* Application::getStyle()
|
||||
{
|
||||
return &Application::currentStyle;
|
||||
}
|
||||
|
||||
void Application::setTheme(Theme theme)
|
||||
{
|
||||
Application::currentTheme = theme;
|
||||
}
|
||||
|
||||
ThemeValues* Application::getThemeValues()
|
||||
{
|
||||
return &Application::currentTheme.colors[Application::currentThemeVariant];
|
||||
}
|
||||
|
||||
ThemeValues* Application::getThemeValuesForVariant(ThemeVariant variant)
|
||||
{
|
||||
return &Application::currentTheme.colors[variant];
|
||||
}
|
||||
|
||||
ThemeVariant Application::getThemeVariant()
|
||||
{
|
||||
return Application::currentThemeVariant;
|
||||
}
|
||||
|
||||
int Application::loadFont(const char* fontName, const char* filePath)
|
||||
{
|
||||
return nvgCreateFont(Application::vg, fontName, filePath);
|
||||
}
|
||||
|
||||
int Application::loadFontFromMemory(const char* fontName, void* address, size_t size, bool freeData)
|
||||
{
|
||||
return nvgCreateFontMem(Application::vg, fontName, (unsigned char*)address, size, freeData);
|
||||
}
|
||||
|
||||
int Application::findFont(const char* fontName)
|
||||
{
|
||||
return nvgFindFont(Application::vg, fontName);
|
||||
}
|
||||
|
||||
void Application::crash(std::string text)
|
||||
{
|
||||
CrashFrame* crashFrame = new CrashFrame(text);
|
||||
Application::pushView(crashFrame);
|
||||
}
|
||||
|
||||
void Application::blockInputs()
|
||||
{
|
||||
Application::blockInputsTokens += 1;
|
||||
}
|
||||
|
||||
void Application::unblockInputs()
|
||||
{
|
||||
if (Application::blockInputsTokens > 0)
|
||||
Application::blockInputsTokens -= 1;
|
||||
}
|
||||
|
||||
NVGcontext* Application::getNVGContext()
|
||||
{
|
||||
return Application::vg;
|
||||
}
|
||||
|
||||
TaskManager* Application::getTaskManager()
|
||||
{
|
||||
return Application::taskManager;
|
||||
}
|
||||
|
||||
void Application::setCommonFooter(std::string footer)
|
||||
{
|
||||
Application::commonFooter = footer;
|
||||
}
|
||||
|
||||
std::string* Application::getCommonFooter()
|
||||
{
|
||||
return &Application::commonFooter;
|
||||
}
|
||||
|
||||
FramerateCounter::FramerateCounter()
|
||||
: Label(LabelStyle::LIST_ITEM, "FPS: ---")
|
||||
{
|
||||
this->setColor(nvgRGB(255, 255, 255));
|
||||
this->setVerticalAlign(NVG_ALIGN_MIDDLE);
|
||||
this->setHorizontalAlign(NVG_ALIGN_RIGHT);
|
||||
this->setBackground(Background::BACKDROP);
|
||||
|
||||
this->lastSecond = cpu_features_get_time_usec() / 1000;
|
||||
}
|
||||
|
||||
void FramerateCounter::frame(FrameContext* ctx)
|
||||
{
|
||||
// Update counter
|
||||
retro_time_t current = cpu_features_get_time_usec() / 1000;
|
||||
|
||||
if (current - this->lastSecond >= 1000)
|
||||
{
|
||||
char fps[10];
|
||||
snprintf(fps, sizeof(fps), "FPS: %03d", this->frames);
|
||||
this->setText(std::string(fps));
|
||||
this->invalidate(); // update width for background
|
||||
|
||||
this->frames = 0;
|
||||
this->lastSecond = current;
|
||||
}
|
||||
|
||||
this->frames++;
|
||||
|
||||
// Regular frame
|
||||
Label::frame(ctx);
|
||||
}
|
||||
|
||||
void Application::setMaximumFPS(unsigned fps)
|
||||
{
|
||||
if (fps == 0)
|
||||
Application::frameTime = 0.0f;
|
||||
else
|
||||
{
|
||||
Application::frameTime = 1000 / (float)fps;
|
||||
}
|
||||
|
||||
Logger::info("Maximum FPS set to %d - using a frame time of %.2f ms", fps, Application::frameTime);
|
||||
}
|
||||
|
||||
std::string Application::getTitle()
|
||||
{
|
||||
return Application::title;
|
||||
}
|
||||
|
||||
GenericEvent* Application::getGlobalFocusChangeEvent()
|
||||
{
|
||||
return &Application::globalFocusChangeEvent;
|
||||
}
|
||||
|
||||
VoidEvent* Application::getGlobalHintsUpdateEvent()
|
||||
{
|
||||
return &Application::globalHintsUpdateEvent;
|
||||
}
|
||||
|
||||
FontStash* Application::getFontStash()
|
||||
{
|
||||
return &Application::fontStash;
|
||||
}
|
||||
|
||||
} // namespace brls
|
||||
376
lib/borealis/library/lib/box_layout.cpp
Normal file
376
lib/borealis/library/lib/box_layout.cpp
Normal file
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 WerWolv
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <borealis/animations.hpp>
|
||||
#include <borealis/application.hpp>
|
||||
#include <borealis/box_layout.hpp>
|
||||
#include <borealis/logger.hpp>
|
||||
#include <iterator>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
BoxLayout::BoxLayout(BoxLayoutOrientation orientation, size_t defaultFocus)
|
||||
: orientation(orientation)
|
||||
, originalDefaultFocus(defaultFocus)
|
||||
, defaultFocusedIndex(defaultFocus)
|
||||
{
|
||||
}
|
||||
|
||||
void BoxLayout::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx)
|
||||
{
|
||||
// Draw children
|
||||
for (BoxLayoutChild* child : this->children)
|
||||
child->view->frame(ctx);
|
||||
}
|
||||
|
||||
void BoxLayout::setGravity(BoxLayoutGravity gravity)
|
||||
{
|
||||
this->gravity = gravity;
|
||||
this->invalidate();
|
||||
}
|
||||
|
||||
void BoxLayout::setSpacing(unsigned spacing)
|
||||
{
|
||||
this->spacing = spacing;
|
||||
this->invalidate();
|
||||
}
|
||||
|
||||
unsigned BoxLayout::getSpacing()
|
||||
{
|
||||
return this->spacing;
|
||||
}
|
||||
|
||||
void BoxLayout::setMargins(unsigned top, unsigned right, unsigned bottom, unsigned left)
|
||||
{
|
||||
this->marginBottom = bottom;
|
||||
this->marginLeft = left;
|
||||
this->marginRight = right;
|
||||
this->marginTop = top;
|
||||
this->invalidate();
|
||||
}
|
||||
|
||||
void BoxLayout::setMarginBottom(unsigned bottom)
|
||||
{
|
||||
this->marginBottom = bottom;
|
||||
this->invalidate();
|
||||
}
|
||||
|
||||
size_t BoxLayout::getViewsCount()
|
||||
{
|
||||
return this->children.size();
|
||||
}
|
||||
|
||||
View* BoxLayout::getDefaultFocus()
|
||||
{
|
||||
// Focus default focus first
|
||||
if (this->defaultFocusedIndex < this->children.size())
|
||||
{
|
||||
View* newFocus = this->children[this->defaultFocusedIndex]->view->getDefaultFocus();
|
||||
|
||||
if (newFocus)
|
||||
return newFocus;
|
||||
}
|
||||
|
||||
// Fallback to finding the first focusable view
|
||||
for (size_t i = 0; i < this->children.size(); i++)
|
||||
{
|
||||
View* newFocus = this->children[i]->view->getDefaultFocus();
|
||||
|
||||
if (newFocus)
|
||||
return newFocus;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
View* BoxLayout::getNextFocus(FocusDirection direction, void* parentUserData)
|
||||
{
|
||||
// Return nullptr immediately if focus direction mismatches the layout direction
|
||||
if ((this->orientation == BoxLayoutOrientation::HORIZONTAL && direction != FocusDirection::LEFT && direction != FocusDirection::RIGHT) || (this->orientation == BoxLayoutOrientation::VERTICAL && direction != FocusDirection::UP && direction != FocusDirection::DOWN))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Traverse the children
|
||||
size_t offset = 1; // which way are we going in the children list
|
||||
|
||||
if ((this->orientation == BoxLayoutOrientation::HORIZONTAL && direction == FocusDirection::LEFT) || (this->orientation == BoxLayoutOrientation::VERTICAL && direction == FocusDirection::UP))
|
||||
{
|
||||
offset = -1;
|
||||
}
|
||||
|
||||
size_t currentFocusIndex = *((size_t*)parentUserData) + offset;
|
||||
View* currentFocus = nullptr;
|
||||
|
||||
while (!currentFocus && currentFocusIndex >= 0 && currentFocusIndex < this->children.size())
|
||||
{
|
||||
currentFocus = this->children[currentFocusIndex]->view->getDefaultFocus();
|
||||
currentFocusIndex += offset;
|
||||
}
|
||||
|
||||
return currentFocus;
|
||||
}
|
||||
|
||||
void BoxLayout::removeView(int index, bool free)
|
||||
{
|
||||
BoxLayoutChild* toRemove = this->children[index];
|
||||
toRemove->view->willDisappear(true);
|
||||
if (free)
|
||||
delete toRemove->view;
|
||||
delete toRemove;
|
||||
this->children.erase(this->children.begin() + index);
|
||||
}
|
||||
|
||||
void BoxLayout::clear(bool free)
|
||||
{
|
||||
while (!this->children.empty())
|
||||
this->removeView(0, free);
|
||||
}
|
||||
|
||||
void BoxLayout::layout(NVGcontext* vg, Style* style, FontStash* stash)
|
||||
{
|
||||
// Vertical orientation
|
||||
if (this->orientation == BoxLayoutOrientation::VERTICAL)
|
||||
{
|
||||
unsigned entriesHeight = 0;
|
||||
int yAdvance = this->y + this->marginTop;
|
||||
|
||||
for (size_t i = 0; i < this->children.size(); i++)
|
||||
{
|
||||
BoxLayoutChild* child = this->children[i];
|
||||
unsigned childHeight = child->view->getHeight();
|
||||
|
||||
if (child->fill)
|
||||
child->view->setBoundaries(this->x + this->marginLeft,
|
||||
yAdvance,
|
||||
this->width - this->marginLeft - this->marginRight,
|
||||
this->y + this->height - yAdvance - this->marginBottom);
|
||||
else
|
||||
child->view->setBoundaries(this->x + this->marginLeft,
|
||||
yAdvance,
|
||||
this->width - this->marginLeft - this->marginRight,
|
||||
child->view->getHeight(false));
|
||||
|
||||
child->view->invalidate(true); // call layout directly in case height is updated
|
||||
childHeight = child->view->getHeight();
|
||||
|
||||
int spacing = (int)this->spacing;
|
||||
View* next = (this->children.size() > 1 && i <= this->children.size() - 2) ? this->children[i + 1]->view : nullptr;
|
||||
|
||||
this->customSpacing(child->view, next, &spacing);
|
||||
|
||||
if (child->view->isCollapsed())
|
||||
spacing = 0;
|
||||
|
||||
if (!child->view->isHidden())
|
||||
entriesHeight += spacing + childHeight;
|
||||
|
||||
yAdvance += spacing + childHeight;
|
||||
}
|
||||
|
||||
// TODO: apply gravity
|
||||
|
||||
// Update height if needed
|
||||
if (this->resize)
|
||||
this->setHeight(entriesHeight - spacing + this->marginTop + this->marginBottom);
|
||||
}
|
||||
// Horizontal orientation
|
||||
else if (this->orientation == BoxLayoutOrientation::HORIZONTAL)
|
||||
{
|
||||
// Layout
|
||||
int xAdvance = this->x + this->marginLeft;
|
||||
for (size_t i = 0; i < this->children.size(); i++)
|
||||
{
|
||||
BoxLayoutChild* child = this->children[i];
|
||||
unsigned childWidth = child->view->getWidth();
|
||||
|
||||
if (child->fill)
|
||||
child->view->setBoundaries(xAdvance,
|
||||
this->y + this->marginTop,
|
||||
this->x + this->width - xAdvance - this->marginRight,
|
||||
this->height - this->marginTop - this->marginBottom);
|
||||
else
|
||||
child->view->setBoundaries(xAdvance,
|
||||
this->y + this->marginTop,
|
||||
childWidth,
|
||||
this->height - this->marginTop - this->marginBottom);
|
||||
|
||||
child->view->invalidate(true); // call layout directly in case width is updated
|
||||
childWidth = child->view->getWidth();
|
||||
|
||||
int spacing = (int)this->spacing;
|
||||
|
||||
View* next = (this->children.size() > 1 && i <= this->children.size() - 2) ? this->children[i + 1]->view : nullptr;
|
||||
|
||||
this->customSpacing(child->view, next, &spacing);
|
||||
|
||||
if (child->view->isCollapsed())
|
||||
spacing = 0;
|
||||
|
||||
xAdvance += spacing + childWidth;
|
||||
}
|
||||
|
||||
// Apply gravity
|
||||
// TODO: more efficient gravity implementation?
|
||||
if (!this->children.empty())
|
||||
{
|
||||
switch (this->gravity)
|
||||
{
|
||||
case BoxLayoutGravity::RIGHT:
|
||||
{
|
||||
// Take the remaining empty space between the last view's
|
||||
// right boundary and ours and push all views by this amount
|
||||
View* lastView = this->children[this->children.size() - 1]->view;
|
||||
|
||||
unsigned lastViewRight = lastView->getX() + lastView->getWidth();
|
||||
unsigned ourRight = this->getX() + this->getWidth();
|
||||
|
||||
if (lastViewRight <= ourRight)
|
||||
{
|
||||
unsigned difference = ourRight - lastViewRight;
|
||||
|
||||
for (BoxLayoutChild* child : this->children)
|
||||
{
|
||||
View* view = child->view;
|
||||
view->setBoundaries(
|
||||
view->getX() + difference,
|
||||
view->getY(),
|
||||
view->getWidth(),
|
||||
view->getHeight());
|
||||
view->invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: update width if needed (introduce entriesWidth)
|
||||
}
|
||||
}
|
||||
|
||||
void BoxLayout::setResize(bool resize)
|
||||
{
|
||||
this->resize = resize;
|
||||
this->invalidate();
|
||||
}
|
||||
|
||||
void BoxLayout::addView(View* view, bool fill, bool resetState)
|
||||
{
|
||||
BoxLayoutChild* child = new BoxLayoutChild();
|
||||
child->view = view;
|
||||
child->fill = fill;
|
||||
|
||||
this->children.push_back(child);
|
||||
|
||||
size_t position = this->children.size() - 1;
|
||||
|
||||
size_t* userdata = (size_t*)malloc(sizeof(size_t));
|
||||
*userdata = position;
|
||||
|
||||
view->setParent(this, userdata);
|
||||
|
||||
view->willAppear(resetState);
|
||||
this->invalidate();
|
||||
}
|
||||
|
||||
View* BoxLayout::getChild(size_t index)
|
||||
{
|
||||
return this->children[index]->view;
|
||||
}
|
||||
|
||||
bool BoxLayout::isEmpty()
|
||||
{
|
||||
return this->children.size() == 0;
|
||||
}
|
||||
|
||||
bool BoxLayout::isChildFocused()
|
||||
{
|
||||
return this->childFocused;
|
||||
}
|
||||
|
||||
void BoxLayout::onChildFocusGained(View* child)
|
||||
{
|
||||
this->childFocused = true;
|
||||
|
||||
// Remember focus if needed
|
||||
if (this->rememberFocus)
|
||||
{
|
||||
size_t index = *((size_t*)child->getParentUserData());
|
||||
this->defaultFocusedIndex = index;
|
||||
}
|
||||
|
||||
View::onChildFocusGained(child);
|
||||
}
|
||||
|
||||
void BoxLayout::onChildFocusLost(View* child)
|
||||
{
|
||||
this->childFocused = false;
|
||||
|
||||
View::onChildFocusLost(child);
|
||||
}
|
||||
|
||||
BoxLayout::~BoxLayout()
|
||||
{
|
||||
for (BoxLayoutChild* child : this->children)
|
||||
{
|
||||
child->view->willDisappear(true);
|
||||
delete child->view;
|
||||
delete child;
|
||||
}
|
||||
|
||||
this->children.clear();
|
||||
}
|
||||
|
||||
void BoxLayout::willAppear(bool resetState)
|
||||
{
|
||||
for (BoxLayoutChild* child : this->children)
|
||||
child->view->willAppear(resetState);
|
||||
}
|
||||
|
||||
void BoxLayout::willDisappear(bool resetState)
|
||||
{
|
||||
for (BoxLayoutChild* child : this->children)
|
||||
child->view->willDisappear(resetState);
|
||||
|
||||
// Reset default focus to original one if needed
|
||||
if (this->rememberFocus)
|
||||
this->defaultFocusedIndex = this->originalDefaultFocus;
|
||||
}
|
||||
|
||||
void BoxLayout::onWindowSizeChanged()
|
||||
{
|
||||
for (BoxLayoutChild* child : this->children)
|
||||
child->view->onWindowSizeChanged();
|
||||
}
|
||||
|
||||
void BoxLayout::setRememberFocus(bool remember)
|
||||
{
|
||||
this->rememberFocus = remember;
|
||||
}
|
||||
|
||||
} // namespace brls
|
||||
213
lib/borealis/library/lib/button.cpp
Normal file
213
lib/borealis/library/lib/button.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019-2020 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <borealis/application.hpp>
|
||||
#include <borealis/button.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
Button::Button(ButtonStyle style)
|
||||
: style(style)
|
||||
{
|
||||
this->registerAction("OK", Key::A, [this] { return this->onClick(); });
|
||||
}
|
||||
|
||||
LabelStyle Button::getLabelStyle()
|
||||
{
|
||||
if (this->style == ButtonStyle::BORDERLESS)
|
||||
return LabelStyle::BUTTON_BORDERLESS;
|
||||
else if (this->style == ButtonStyle::DIALOG)
|
||||
return LabelStyle::BUTTON_DIALOG;
|
||||
else if (this->style == ButtonStyle::CRASH)
|
||||
return LabelStyle::CRASH;
|
||||
|
||||
if (this->state == ButtonState::DISABLED)
|
||||
return LabelStyle::BUTTON_PLAIN_DISABLED;
|
||||
else
|
||||
return LabelStyle::BUTTON_PLAIN;
|
||||
}
|
||||
|
||||
Button::~Button()
|
||||
{
|
||||
if (this->label != nullptr)
|
||||
delete this->label;
|
||||
if (this->image != nullptr)
|
||||
delete this->image;
|
||||
}
|
||||
|
||||
void Button::layout(NVGcontext* vg, Style* style, FontStash* stash)
|
||||
{
|
||||
unsigned imageWidth = this->label ? this->getHeight() : this->getWidth();
|
||||
unsigned imageHeight = this->getHeight();
|
||||
|
||||
if (!this->image)
|
||||
imageWidth = 0;
|
||||
|
||||
if (this->label != nullptr)
|
||||
{
|
||||
this->label->setWidth(this->getWidth() - imageWidth);
|
||||
this->label->invalidate(true);
|
||||
this->label->setBoundaries(
|
||||
this->x + imageWidth,
|
||||
this->y + this->getHeight() / 2 - this->label->getHeight() / 2,
|
||||
this->label->getWidth(),
|
||||
this->label->getHeight());
|
||||
this->label->invalidate();
|
||||
}
|
||||
if (this->image != nullptr)
|
||||
{
|
||||
this->image->setHeight(imageHeight);
|
||||
this->image->setWidth(imageWidth);
|
||||
this->image->invalidate(true);
|
||||
this->image->setBoundaries(
|
||||
this->x,
|
||||
this->y + this->getHeight() / 2 - this->image->getHeight() / 2,
|
||||
this->image->getWidth(),
|
||||
this->image->getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
Button* Button::setLabel(std::string label)
|
||||
{
|
||||
if (this->label != nullptr)
|
||||
delete this->label;
|
||||
|
||||
this->label = new Label(this->getLabelStyle(), label, true);
|
||||
this->label->setHorizontalAlign(NVG_ALIGN_CENTER);
|
||||
this->label->setParent(this);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Button* Button::setImage(std::string path)
|
||||
{
|
||||
this->image = new Image(path);
|
||||
this->image->setParent(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
Button* Button::setImage(unsigned char* buffer, size_t bufferSize)
|
||||
{
|
||||
this->image = new Image(buffer, bufferSize);
|
||||
this->image->setParent(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
void Button::setState(ButtonState state)
|
||||
{
|
||||
this->state = state;
|
||||
if (this->label != nullptr)
|
||||
this->label->setStyle(this->getLabelStyle());
|
||||
}
|
||||
|
||||
ButtonState Button::getState()
|
||||
{
|
||||
return this->state;
|
||||
}
|
||||
|
||||
void Button::getHighlightInsets(unsigned* top, unsigned* right, unsigned* bottom, unsigned* left)
|
||||
{
|
||||
if (this->style == ButtonStyle::DIALOG)
|
||||
{
|
||||
View::getHighlightInsets(top, right, bottom, left);
|
||||
*right -= 1;
|
||||
return;
|
||||
}
|
||||
|
||||
Style* style = Application::getStyle();
|
||||
*top = style->Button.highlightInset;
|
||||
*right = style->Button.highlightInset;
|
||||
*bottom = style->Button.highlightInset;
|
||||
*left = style->Button.highlightInset;
|
||||
}
|
||||
|
||||
void Button::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx)
|
||||
{
|
||||
float cornerRadius = this->cornerRadiusOverride ? this->cornerRadiusOverride : (float)style->Button.cornerRadius;
|
||||
|
||||
// Background
|
||||
switch (this->style)
|
||||
{
|
||||
case ButtonStyle::PLAIN:
|
||||
{
|
||||
nvgFillColor(vg, a(this->state == ButtonState::DISABLED ? ctx->theme->buttonPlainDisabledBackgroundColor : ctx->theme->buttonPlainEnabledBackgroundColor));
|
||||
nvgBeginPath(vg);
|
||||
nvgRoundedRect(vg, x, y, width, height, cornerRadius);
|
||||
nvgFill(vg);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Shadow
|
||||
if (this->state == ButtonState::ENABLED && this->style == ButtonStyle::PLAIN)
|
||||
{
|
||||
float shadowWidth = style->Button.shadowWidth;
|
||||
float shadowFeather = style->Button.shadowFeather;
|
||||
float shadowOpacity = style->Button.shadowOpacity;
|
||||
float shadowOffset = style->Button.shadowOffset;
|
||||
|
||||
NVGpaint shadowPaint = nvgBoxGradient(vg,
|
||||
x, y + shadowWidth,
|
||||
width, height,
|
||||
cornerRadius * 2, shadowFeather,
|
||||
RGBA(0, 0, 0, shadowOpacity * alpha), transparent);
|
||||
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, x - shadowOffset, y - shadowOffset,
|
||||
width + shadowOffset * 2, height + shadowOffset * 3);
|
||||
nvgRoundedRect(vg, x, y, width, height, cornerRadius);
|
||||
nvgPathWinding(vg, NVG_HOLE);
|
||||
nvgFillPaint(vg, shadowPaint);
|
||||
nvgFill(vg);
|
||||
}
|
||||
|
||||
// Label
|
||||
if (this->label != nullptr)
|
||||
this->label->frame(ctx);
|
||||
|
||||
if (this->image != nullptr)
|
||||
this->image->frame(ctx);
|
||||
}
|
||||
|
||||
bool Button::onClick()
|
||||
{
|
||||
if (this->state == ButtonState::DISABLED)
|
||||
return false;
|
||||
|
||||
return this->clickEvent.fire(this);
|
||||
}
|
||||
|
||||
GenericEvent* Button::getClickEvent()
|
||||
{
|
||||
return &this->clickEvent;
|
||||
}
|
||||
|
||||
void Button::setCornerRadius(float cornerRadius)
|
||||
{
|
||||
this->cornerRadiusOverride = cornerRadius;
|
||||
|
||||
if (this->image != nullptr)
|
||||
this->image->setCornerRadius(cornerRadius);
|
||||
}
|
||||
} // namespace brls
|
||||
151
lib/borealis/library/lib/crash_frame.cpp
Normal file
151
lib/borealis/library/lib/crash_frame.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019-2020 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <borealis/animations.hpp>
|
||||
#include <borealis/application.hpp>
|
||||
#include <borealis/crash_frame.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
CrashFrame::CrashFrame(std::string text)
|
||||
{
|
||||
// Label
|
||||
this->label = new Label(LabelStyle::CRASH, text, true);
|
||||
this->label->setHorizontalAlign(NVG_ALIGN_CENTER);
|
||||
this->label->setParent(this);
|
||||
|
||||
// Button
|
||||
this->button = (new Button(ButtonStyle::CRASH))->setLabel("OK");
|
||||
this->button->setParent(this);
|
||||
this->button->alpha = 0.0f;
|
||||
this->button->getClickEvent()->subscribe([](View* view) { Application::quit(); });
|
||||
this->button->overrideThemeVariant(Application::getThemeValuesForVariant(ThemeVariant_DARK));
|
||||
|
||||
// Hint
|
||||
this->hint = new Hint();
|
||||
this->hint->setParent(this);
|
||||
}
|
||||
|
||||
void CrashFrame::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx)
|
||||
{
|
||||
nvgSave(vg);
|
||||
|
||||
// Background
|
||||
nvgFillColor(vg, RGB(0, 0, 0));
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, x, y, width, height);
|
||||
nvgFill(vg);
|
||||
|
||||
// Scale
|
||||
float scale = (this->alpha + 2.0f) / 3.0f;
|
||||
nvgTranslate(vg, (1.0f - scale) * width * 0.5f, (1.0f - scale) * height * 0.5f);
|
||||
nvgScale(vg, scale, scale);
|
||||
|
||||
// Label
|
||||
this->label->frame(ctx);
|
||||
|
||||
// [!] box
|
||||
unsigned boxSize = style->CrashFrame.boxSize;
|
||||
nvgStrokeColor(vg, RGB(255, 255, 255));
|
||||
nvgStrokeWidth(vg, style->CrashFrame.boxStrokeWidth);
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, x + width / 2 - boxSize / 2, y + style->CrashFrame.boxSpacing, boxSize, boxSize);
|
||||
nvgStroke(vg);
|
||||
|
||||
nvgFillColor(vg, RGB(255, 255, 255));
|
||||
|
||||
nvgFontSize(vg, (float)style->CrashFrame.boxSize / 1.25f);
|
||||
nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
|
||||
nvgBeginPath(vg);
|
||||
nvgText(vg, x + width / 2, y + style->CrashFrame.boxSpacing + boxSize / 2, "!", nullptr);
|
||||
nvgFill(vg);
|
||||
|
||||
// End scale
|
||||
nvgResetTransform(vg);
|
||||
nvgRestore(vg);
|
||||
|
||||
// Footer
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, x + style->AppletFrame.separatorSpacing, y + height - style->AppletFrame.footerHeight, width - style->AppletFrame.separatorSpacing * 2, 1);
|
||||
nvgFill(vg);
|
||||
|
||||
nvgFontSize(vg, style->AppletFrame.footerTextSize);
|
||||
nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
|
||||
nvgBeginPath(vg);
|
||||
nvgText(vg, x + style->AppletFrame.separatorSpacing + style->AppletFrame.footerTextSpacing, y + height - style->AppletFrame.footerHeight / 2, Application::getTitle().c_str(), nullptr);
|
||||
|
||||
// Button
|
||||
this->button->frame(ctx);
|
||||
|
||||
// Hint
|
||||
this->hint->frame(ctx);
|
||||
}
|
||||
|
||||
void CrashFrame::onShowAnimationEnd()
|
||||
{
|
||||
this->button->show([]() {});
|
||||
}
|
||||
|
||||
View* CrashFrame::getDefaultFocus()
|
||||
{
|
||||
return this->button->getDefaultFocus();
|
||||
}
|
||||
|
||||
void CrashFrame::layout(NVGcontext* vg, Style* style, FontStash* stash)
|
||||
{
|
||||
// Label
|
||||
this->label->setWidth(roundf((float)this->width * style->CrashFrame.labelWidth));
|
||||
this->label->invalidate(true);
|
||||
|
||||
this->label->setBoundaries(
|
||||
this->x + this->width / 2 - this->label->getWidth() / 2,
|
||||
this->y + (this->height - style->AppletFrame.footerHeight) / 2,
|
||||
this->label->getWidth(),
|
||||
this->label->getHeight());
|
||||
|
||||
// Button
|
||||
this->button->setBoundaries(
|
||||
this->x + this->width / 2 - style->CrashFrame.buttonWidth / 2,
|
||||
this->y + this->height - style->AppletFrame.footerHeight - style->CrashFrame.boxSpacing - style->CrashFrame.buttonHeight,
|
||||
style->CrashFrame.buttonWidth,
|
||||
style->CrashFrame.buttonHeight);
|
||||
this->button->invalidate();
|
||||
|
||||
// Hint
|
||||
// TODO: convert the bottom-left footer into a Label to get its width and avoid clipping with the hint
|
||||
unsigned hintWidth = this->width - style->AppletFrame.separatorSpacing * 2 - style->AppletFrame.footerTextSpacing * 2;
|
||||
|
||||
this->hint->setBoundaries(
|
||||
this->x + this->width - hintWidth - style->AppletFrame.separatorSpacing - style->AppletFrame.footerTextSpacing,
|
||||
this->y + this->height - style->AppletFrame.footerHeight,
|
||||
hintWidth,
|
||||
style->AppletFrame.footerHeight);
|
||||
this->hint->invalidate();
|
||||
}
|
||||
|
||||
CrashFrame::~CrashFrame()
|
||||
{
|
||||
delete this->label;
|
||||
delete this->hint;
|
||||
}
|
||||
|
||||
} // namespace brls
|
||||
342
lib/borealis/library/lib/dialog.cpp
Normal file
342
lib/borealis/library/lib/dialog.cpp
Normal file
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019-2020 natinusala
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <borealis/application.hpp>
|
||||
#include <borealis/button.hpp>
|
||||
#include <borealis/dialog.hpp>
|
||||
|
||||
// TODO: different open animation?
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
Dialog::Dialog(View* contentView)
|
||||
: contentView(contentView)
|
||||
{
|
||||
if (contentView)
|
||||
contentView->setParent(this);
|
||||
|
||||
this->registerAction("Back", Key::B, [this] { return this->onCancel(); });
|
||||
}
|
||||
|
||||
Dialog::Dialog(std::string text)
|
||||
: Dialog(new Label(LabelStyle::DIALOG, text, true))
|
||||
{
|
||||
}
|
||||
|
||||
void Dialog::addButton(std::string label, GenericEvent::Callback cb)
|
||||
{
|
||||
if (this->buttons.size() >= 3)
|
||||
return;
|
||||
|
||||
DialogButton* button = new DialogButton();
|
||||
button->label = label;
|
||||
button->cb = cb;
|
||||
|
||||
this->buttons.push_back(button);
|
||||
|
||||
this->rebuildButtons();
|
||||
this->invalidate();
|
||||
}
|
||||
|
||||
void Dialog::open()
|
||||
{
|
||||
Application::pushView(this);
|
||||
|
||||
if (this->buttons.size() == 0)
|
||||
Application::blockInputs();
|
||||
}
|
||||
|
||||
// TODO: do something better in case another view was pushed in the meantime
|
||||
void Dialog::close(std::function<void(void)> cb)
|
||||
{
|
||||
Application::popView(ViewAnimation::FADE, cb);
|
||||
|
||||
if (this->buttons.size() == 0)
|
||||
Application::unblockInputs();
|
||||
}
|
||||
|
||||
void Dialog::setCancelable(bool cancelable)
|
||||
{
|
||||
this->cancelable = cancelable;
|
||||
}
|
||||
|
||||
void Dialog::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx)
|
||||
{
|
||||
// Backdrop
|
||||
nvgFillColor(vg, a(ctx->theme->dialogBackdrop));
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, x, y, width, height);
|
||||
nvgFill(vg);
|
||||
|
||||
// Shadow
|
||||
float shadowWidth = style->Dialog.shadowWidth;
|
||||
float shadowFeather = style->Dialog.shadowFeather;
|
||||
float shadowOpacity = style->Dialog.shadowOpacity;
|
||||
float shadowOffset = style->Dialog.shadowOffset;
|
||||
|
||||
NVGpaint shadowPaint = nvgBoxGradient(vg,
|
||||
this->frameX, this->frameY + shadowWidth,
|
||||
this->frameWidth, this->frameHeight,
|
||||
style->Dialog.cornerRadius * 2, shadowFeather,
|
||||
RGBA(0, 0, 0, shadowOpacity * alpha), transparent);
|
||||
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, this->frameX - shadowOffset, this->frameY - shadowOffset,
|
||||
this->frameWidth + shadowOffset * 2, this->frameHeight + shadowOffset * 3);
|
||||
nvgRoundedRect(vg, this->frameX, this->frameY, this->frameWidth, this->frameHeight, style->Dialog.cornerRadius);
|
||||
nvgPathWinding(vg, NVG_HOLE);
|
||||
nvgFillPaint(vg, shadowPaint);
|
||||
nvgFill(vg);
|
||||
|
||||
// Frame
|
||||
nvgFillColor(vg, a(ctx->theme->dialogColor));
|
||||
nvgBeginPath(vg);
|
||||
nvgRoundedRect(vg, this->frameX, this->frameY, this->frameWidth, this->frameHeight, style->Dialog.cornerRadius);
|
||||
nvgFill(vg);
|
||||
|
||||
// Content view
|
||||
if (this->contentView)
|
||||
this->contentView->frame(ctx);
|
||||
|
||||
// Buttons separator
|
||||
if (this->buttons.size() > 0)
|
||||
{
|
||||
unsigned buttonsHeight = this->getButtonsHeight();
|
||||
nvgFillColor(vg, a(ctx->theme->dialogButtonSeparatorColor));
|
||||
|
||||
// First vertical separator
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, this->frameX, this->frameY + this->frameHeight - buttonsHeight, this->frameWidth, style->Dialog.buttonSeparatorHeight);
|
||||
nvgFill(vg);
|
||||
|
||||
// Second vertical separator
|
||||
if (this->buttons.size() == 3)
|
||||
{
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, this->frameX, this->frameY + this->frameHeight - style->Dialog.buttonHeight, this->frameWidth, style->Dialog.buttonSeparatorHeight);
|
||||
nvgFill(vg);
|
||||
}
|
||||
|
||||
// Horizontal separator
|
||||
if (this->buttons.size() >= 2)
|
||||
{
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(
|
||||
vg,
|
||||
this->frameX + this->frameWidth / 2 + style->Dialog.buttonSeparatorHeight / 2,
|
||||
this->frameY + this->frameHeight - style->Dialog.buttonHeight + 1, // offset by 1 to fix aliasing artifact
|
||||
style->Dialog.buttonSeparatorHeight,
|
||||
style->Dialog.buttonHeight - 1);
|
||||
nvgFill(vg);
|
||||
}
|
||||
}
|
||||
|
||||
// Buttons
|
||||
if (this->verticalButtonsLayout)
|
||||
this->verticalButtonsLayout->frame(ctx);
|
||||
}
|
||||
|
||||
View* Dialog::getDefaultFocus()
|
||||
{
|
||||
if (this->buttons.size() > 0 && this->verticalButtonsLayout)
|
||||
return this->verticalButtonsLayout->getDefaultFocus();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Dialog::onCancel()
|
||||
{
|
||||
if (this->cancelable)
|
||||
this->close();
|
||||
|
||||
return this->cancelable;
|
||||
}
|
||||
|
||||
unsigned Dialog::getButtonsHeight()
|
||||
{
|
||||
Style* style = Application::getStyle();
|
||||
if (this->buttons.size() == 3)
|
||||
return style->Dialog.buttonHeight * 2;
|
||||
else if (this->buttons.size() > 0) // 1 or 2
|
||||
return style->Dialog.buttonHeight;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Dialog::layout(NVGcontext* vg, Style* style, FontStash* stash)
|
||||
{
|
||||
this->frameWidth = style->Dialog.width;
|
||||
this->frameHeight = style->Dialog.height;
|
||||
|
||||
unsigned buttonsHeight = this->getButtonsHeight();
|
||||
this->frameHeight += buttonsHeight;
|
||||
|
||||
this->frameX = getWidth() / 2 - this->frameWidth / 2;
|
||||
this->frameY = getHeight() / 2 - this->frameHeight / 2;
|
||||
|
||||
unsigned contentX = this->frameX + style->Dialog.paddingLeftRight;
|
||||
unsigned contentY = this->frameY + style->Dialog.paddingTopBottom;
|
||||
unsigned contentWidth = this->frameWidth - style->Dialog.paddingLeftRight * 2;
|
||||
unsigned contentHeight = this->frameHeight - style->Dialog.paddingTopBottom * 2 - buttonsHeight;
|
||||
|
||||
if (this->contentView)
|
||||
{
|
||||
// First layout to get height
|
||||
this->contentView->setBoundaries(
|
||||
contentX,
|
||||
contentY,
|
||||
contentWidth,
|
||||
contentHeight);
|
||||
|
||||
this->contentView->invalidate(true); // layout directly to get height
|
||||
|
||||
// Center the content view in the dialog
|
||||
// or resize it if needed
|
||||
unsigned newContentHeight = this->contentView->getHeight();
|
||||
|
||||
int difference = contentHeight - newContentHeight;
|
||||
|
||||
if (difference < 0)
|
||||
{
|
||||
this->frameHeight += -difference;
|
||||
}
|
||||
else
|
||||
{
|
||||
contentY += difference / 2;
|
||||
|
||||
this->contentView->setBoundaries(
|
||||
contentX,
|
||||
contentY,
|
||||
contentWidth,
|
||||
contentHeight);
|
||||
|
||||
this->contentView->invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// Buttons
|
||||
if (this->verticalButtonsLayout)
|
||||
{
|
||||
this->verticalButtonsLayout->setBoundaries(
|
||||
this->frameX,
|
||||
this->frameY + this->frameHeight - buttonsHeight,
|
||||
this->frameWidth,
|
||||
style->Dialog.buttonHeight);
|
||||
|
||||
// Only one big button
|
||||
if (this->buttons.size() == 1)
|
||||
{
|
||||
this->verticalButtonsLayout->getChild(0)->setHeight(style->Dialog.buttonHeight);
|
||||
}
|
||||
// Two buttons on one row
|
||||
else if (this->buttons.size() == 2)
|
||||
{
|
||||
this->horizontalButtonsLayout->setHeight(style->Dialog.buttonHeight);
|
||||
|
||||
this->horizontalButtonsLayout->getChild(0)->setWidth(this->frameWidth / 2);
|
||||
this->horizontalButtonsLayout->getChild(1)->setWidth(this->frameWidth / 2);
|
||||
}
|
||||
// Two rows: one with one button and one with two
|
||||
else if (this->buttons.size() == 3)
|
||||
{
|
||||
this->verticalButtonsLayout->getChild(0)->setHeight(style->Dialog.buttonHeight);
|
||||
|
||||
this->horizontalButtonsLayout->setHeight(style->Dialog.buttonHeight);
|
||||
|
||||
this->horizontalButtonsLayout->getChild(0)->setWidth(this->frameWidth / 2);
|
||||
this->horizontalButtonsLayout->getChild(1)->setWidth(this->frameWidth / 2);
|
||||
}
|
||||
|
||||
this->verticalButtonsLayout->invalidate();
|
||||
if (this->horizontalButtonsLayout)
|
||||
this->horizontalButtonsLayout->invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void Dialog::rebuildButtons()
|
||||
{
|
||||
if (this->verticalButtonsLayout)
|
||||
delete this->verticalButtonsLayout;
|
||||
this->verticalButtonsLayout = nullptr;
|
||||
|
||||
// horizontal box layout will be deleted by
|
||||
// the vertical layout destructor
|
||||
|
||||
if (this->buttons.size() > 0)
|
||||
{
|
||||
this->verticalButtonsLayout = new BoxLayout(BoxLayoutOrientation::VERTICAL);
|
||||
this->verticalButtonsLayout->setParent(this);
|
||||
|
||||
// Only one big button
|
||||
if (this->buttons.size() == 1)
|
||||
{
|
||||
Button* button = (new Button(ButtonStyle::DIALOG))->setLabel(this->buttons[0]->label);
|
||||
button->getClickEvent()->subscribe(this->buttons[0]->cb);
|
||||
this->verticalButtonsLayout->addView(button);
|
||||
}
|
||||
// Two buttons on one row
|
||||
else if (this->buttons.size() == 2)
|
||||
{
|
||||
this->horizontalButtonsLayout = new BoxLayout(BoxLayoutOrientation::HORIZONTAL);
|
||||
this->verticalButtonsLayout->addView(this->horizontalButtonsLayout);
|
||||
|
||||
for (DialogButton* dialogButton : this->buttons)
|
||||
{
|
||||
Button* button = (new Button(ButtonStyle::DIALOG))->setLabel(dialogButton->label);
|
||||
button->getClickEvent()->subscribe(dialogButton->cb);
|
||||
this->horizontalButtonsLayout->addView(button);
|
||||
}
|
||||
}
|
||||
// Two rows: one with one button and one with two
|
||||
else if (this->buttons.size() == 3)
|
||||
{
|
||||
Button* button = (new Button(ButtonStyle::DIALOG))->setLabel(this->buttons[0]->label);
|
||||
button->getClickEvent()->subscribe(this->buttons[0]->cb);
|
||||
this->verticalButtonsLayout->addView(button);
|
||||
|
||||
this->horizontalButtonsLayout = new BoxLayout(BoxLayoutOrientation::HORIZONTAL);
|
||||
this->verticalButtonsLayout->addView(this->horizontalButtonsLayout);
|
||||
|
||||
for (size_t i = 1; i < this->buttons.size(); i++)
|
||||
{
|
||||
DialogButton* dialogButton = this->buttons[i];
|
||||
Button* button = (new Button(ButtonStyle::DIALOG))->setLabel(dialogButton->label);
|
||||
button->getClickEvent()->subscribe(dialogButton->cb);
|
||||
this->horizontalButtonsLayout->addView(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Dialog::~Dialog()
|
||||
{
|
||||
if (this->contentView)
|
||||
delete this->contentView;
|
||||
|
||||
if (this->verticalButtonsLayout)
|
||||
delete this->verticalButtonsLayout;
|
||||
|
||||
for (DialogButton* dialogButton : this->buttons)
|
||||
delete dialogButton;
|
||||
|
||||
// horizontal box layout will be deleted by
|
||||
// the vertical layout destructor
|
||||
}
|
||||
|
||||
} // namespace brls
|
||||
214
lib/borealis/library/lib/dropdown.cpp
Normal file
214
lib/borealis/library/lib/dropdown.cpp
Normal file
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019-2020 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <borealis/animations.hpp>
|
||||
#include <borealis/application.hpp>
|
||||
#include <borealis/dropdown.hpp>
|
||||
#include <borealis/logger.hpp>
|
||||
|
||||
#define SELECT_VIEW_MAX_ITEMS 6 // for max height
|
||||
|
||||
#define min(a, b) ((a < b) ? a : b)
|
||||
|
||||
// TODO: Turns out the fade out animation is the same as the fade in (top -> bottom)
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
Dropdown::Dropdown(std::string title, std::vector<std::string> values, ValueSelectedEvent::Callback cb, size_t selected)
|
||||
: title(title)
|
||||
{
|
||||
Style* style = Application::getStyle();
|
||||
|
||||
this->valueEvent.subscribe(cb);
|
||||
|
||||
this->topOffset = (float)style->Dropdown.listPadding / 8.0f;
|
||||
|
||||
this->valuesCount = values.size();
|
||||
|
||||
this->list = new List(selected);
|
||||
this->list->setParent(this);
|
||||
this->list->setMargins(1, 0, 1, 0);
|
||||
|
||||
for (size_t i = 0; i < values.size(); i++)
|
||||
{
|
||||
std::string value = values[i];
|
||||
|
||||
ListItem* item = new ListItem(value);
|
||||
|
||||
if (i == selected)
|
||||
item->setChecked(true);
|
||||
|
||||
item->setHeight(style->Dropdown.listItemHeight);
|
||||
item->setTextSize(style->Dropdown.listItemTextSize);
|
||||
|
||||
item->getClickEvent()->subscribe([this, i](View* view) {
|
||||
this->valueEvent.fire(i);
|
||||
Application::popView();
|
||||
});
|
||||
|
||||
this->list->addView(item);
|
||||
}
|
||||
|
||||
this->hint = new Hint();
|
||||
this->hint->setParent(this);
|
||||
|
||||
this->registerAction("Back", Key::B, [this] { return this->onCancel(); });
|
||||
}
|
||||
|
||||
void Dropdown::show(std::function<void(void)> cb, bool animate, ViewAnimation animation)
|
||||
{
|
||||
View::show(cb);
|
||||
|
||||
menu_animation_ctx_entry_t entry;
|
||||
|
||||
entry.duration = this->getShowAnimationDuration(animation);
|
||||
entry.easing_enum = EASING_OUT_QUAD;
|
||||
entry.subject = &this->topOffset;
|
||||
entry.tag = (uintptr_t) nullptr;
|
||||
entry.target_value = 0.0f;
|
||||
entry.tick = [this](void* userdata) { this->invalidate(); };
|
||||
entry.userdata = nullptr;
|
||||
|
||||
menu_animation_push(&entry);
|
||||
}
|
||||
|
||||
void Dropdown::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx)
|
||||
{
|
||||
unsigned top = this->list->getY() - style->Dropdown.headerHeight - style->Dropdown.listPadding;
|
||||
|
||||
// Backdrop
|
||||
nvgFillColor(vg, a(ctx->theme->dropdownBackgroundColor));
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, x, y, width, top);
|
||||
nvgFill(vg);
|
||||
|
||||
// TODO: Shadow
|
||||
|
||||
// Background
|
||||
nvgFillColor(vg, a(ctx->theme->sidebarColor));
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, x, top, width, height - top);
|
||||
nvgFill(vg);
|
||||
|
||||
// List
|
||||
this->list->frame(ctx);
|
||||
|
||||
// Footer
|
||||
this->hint->frame(ctx);
|
||||
|
||||
nvgFillColor(vg, ctx->theme->separatorColor); // we purposely don't apply opacity
|
||||
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, x + style->AppletFrame.separatorSpacing, y + height - style->AppletFrame.footerHeight, width - style->AppletFrame.separatorSpacing * 2, 1);
|
||||
nvgFill(vg);
|
||||
|
||||
nvgFillColor(vg, ctx->theme->textColor); // we purposely don't apply opacity
|
||||
nvgFontSize(vg, style->AppletFrame.footerTextSize);
|
||||
nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
|
||||
nvgBeginPath(vg);
|
||||
nvgText(vg, x + style->AppletFrame.separatorSpacing + style->AppletFrame.footerTextSpacing, y + height - style->AppletFrame.footerHeight / 2, Application::getCommonFooter()->c_str(), nullptr);
|
||||
|
||||
// Header
|
||||
nvgFillColor(vg, a(ctx->theme->separatorColor));
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, x + style->AppletFrame.separatorSpacing, top + style->Dropdown.headerHeight - 1, width - style->AppletFrame.separatorSpacing * 2, 1);
|
||||
nvgFill(vg);
|
||||
|
||||
nvgBeginPath(vg);
|
||||
nvgFillColor(vg, a(ctx->theme->textColor));
|
||||
nvgFontFaceId(vg, ctx->fontStash->regular);
|
||||
nvgFontSize(vg, style->Dropdown.headerFontSize);
|
||||
nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
|
||||
nvgText(vg, x + style->Dropdown.headerPadding, top + style->Dropdown.headerHeight / 2, this->title.c_str(), nullptr);
|
||||
}
|
||||
|
||||
bool Dropdown::onCancel()
|
||||
{
|
||||
this->valueEvent.fire(-1);
|
||||
Application::popView();
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned Dropdown::getShowAnimationDuration(ViewAnimation animation)
|
||||
{
|
||||
return View::getShowAnimationDuration(animation) / 2;
|
||||
}
|
||||
|
||||
void Dropdown::layout(NVGcontext* vg, Style* style, FontStash* stash)
|
||||
{
|
||||
// Layout and move the list
|
||||
unsigned listHeight = min(SELECT_VIEW_MAX_ITEMS, this->valuesCount) * style->Dropdown.listItemHeight - (unsigned)this->topOffset;
|
||||
unsigned listWidth = style->Dropdown.listWidth + style->List.marginLeftRight * 2;
|
||||
|
||||
this->list->setBoundaries(
|
||||
this->width / 2 - listWidth / 2,
|
||||
this->height - style->AppletFrame.footerHeight - listHeight - style->Dropdown.listPadding + (unsigned)this->topOffset,
|
||||
listWidth,
|
||||
listHeight);
|
||||
this->list->invalidate(true); // call layout directly to update scrolling
|
||||
|
||||
// Hint
|
||||
// TODO: convert the bottom-left footer into a Label to get its width and avoid clipping with the hint
|
||||
unsigned hintWidth = this->width - style->AppletFrame.separatorSpacing * 2 - style->AppletFrame.footerTextSpacing * 2;
|
||||
|
||||
this->hint->setBoundaries(
|
||||
this->x + this->width - hintWidth - style->AppletFrame.separatorSpacing - style->AppletFrame.footerTextSpacing,
|
||||
this->y + this->height - style->AppletFrame.footerHeight,
|
||||
hintWidth,
|
||||
style->AppletFrame.footerHeight);
|
||||
this->hint->invalidate();
|
||||
}
|
||||
|
||||
View* Dropdown::getDefaultFocus()
|
||||
{
|
||||
return this->list->getDefaultFocus();
|
||||
}
|
||||
|
||||
void Dropdown::open(std::string title, std::vector<std::string> values, ValueSelectedEvent::Callback cb, int selected)
|
||||
{
|
||||
Dropdown* dropdown = new Dropdown(title, values, cb, selected);
|
||||
Application::pushView(dropdown);
|
||||
}
|
||||
|
||||
void Dropdown::willAppear(bool resetState)
|
||||
{
|
||||
if (this->list)
|
||||
this->list->willAppear(resetState);
|
||||
|
||||
if (this->hint)
|
||||
this->hint->willAppear(resetState);
|
||||
}
|
||||
|
||||
void Dropdown::willDisappear(bool resetState)
|
||||
{
|
||||
if (this->list)
|
||||
this->list->willDisappear(resetState);
|
||||
|
||||
if (this->hint)
|
||||
this->hint->willDisappear(resetState);
|
||||
}
|
||||
|
||||
Dropdown::~Dropdown()
|
||||
{
|
||||
delete this->list;
|
||||
delete this->hint;
|
||||
}
|
||||
|
||||
} // namespace brls
|
||||
1413
lib/borealis/library/lib/extern/glad/glad.c
vendored
Normal file
1413
lib/borealis/library/lib/extern/glad/glad.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5
lib/borealis/library/lib/extern/libretro-common/.gitignore
vendored
Normal file
5
lib/borealis/library/lib/extern/libretro-common/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
*.dll
|
||||
*.exe
|
||||
*.c~
|
||||
*.un~
|
||||
*.o
|
||||
69
lib/borealis/library/lib/extern/libretro-common/compat/compat_strl.c
vendored
Normal file
69
lib/borealis/library/lib/extern/libretro-common/compat/compat_strl.c
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (compat_strl.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <compat/strl.h>
|
||||
|
||||
/* Implementation of strlcpy()/strlcat() based on OpenBSD. */
|
||||
|
||||
#ifndef __MACH__
|
||||
|
||||
size_t strlcpy(char *dest, const char *source, size_t size)
|
||||
{
|
||||
size_t src_size = 0;
|
||||
size_t n = size;
|
||||
|
||||
if (n)
|
||||
while (--n && (*dest++ = *source++)) src_size++;
|
||||
|
||||
if (!n)
|
||||
{
|
||||
if (size) *dest = '\0';
|
||||
while (*source++) src_size++;
|
||||
}
|
||||
|
||||
return src_size;
|
||||
}
|
||||
|
||||
size_t strlcat(char *dest, const char *source, size_t size)
|
||||
{
|
||||
size_t len = strlen(dest);
|
||||
|
||||
dest += len;
|
||||
|
||||
if (len > size)
|
||||
size = 0;
|
||||
else
|
||||
size -= len;
|
||||
|
||||
return len + strlcpy(dest, source, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
char *strldup(const char *s, size_t n)
|
||||
{
|
||||
char *dst = (char*)malloc(sizeof(char) * (n + 1));
|
||||
strlcpy(dst, s, n);
|
||||
return dst;
|
||||
}
|
||||
510
lib/borealis/library/lib/extern/libretro-common/encodings/encoding_utf.c
vendored
Normal file
510
lib/borealis/library/lib/extern/libretro-common/encodings/encoding_utf.c
vendored
Normal file
@@ -0,0 +1,510 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (encoding_utf.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include <compat/strl.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
#include <encodings/utf.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#include <windows.h>
|
||||
#elif defined(_XBOX)
|
||||
#include <xtl.h>
|
||||
#endif
|
||||
|
||||
static unsigned leading_ones(uint8_t c)
|
||||
{
|
||||
unsigned ones = 0;
|
||||
while (c & 0x80)
|
||||
{
|
||||
ones++;
|
||||
c <<= 1;
|
||||
}
|
||||
|
||||
return ones;
|
||||
}
|
||||
|
||||
/* Simple implementation. Assumes the sequence is
|
||||
* properly synchronized and terminated. */
|
||||
|
||||
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
||||
const char *in, size_t in_size)
|
||||
{
|
||||
unsigned i;
|
||||
size_t ret = 0;
|
||||
while (in_size && out_chars)
|
||||
{
|
||||
unsigned extra, shift;
|
||||
uint32_t c;
|
||||
uint8_t first = *in++;
|
||||
unsigned ones = leading_ones(first);
|
||||
|
||||
if (ones > 6 || ones == 1) /* Invalid or desync. */
|
||||
break;
|
||||
|
||||
extra = ones ? ones - 1 : ones;
|
||||
if (1 + extra > in_size) /* Overflow. */
|
||||
break;
|
||||
|
||||
shift = (extra - 1) * 6;
|
||||
c = (first & ((1 << (7 - ones)) - 1)) << (6 * extra);
|
||||
|
||||
for (i = 0; i < extra; i++, in++, shift -= 6)
|
||||
c |= (*in & 0x3f) << shift;
|
||||
|
||||
*out++ = c;
|
||||
in_size -= 1 + extra;
|
||||
out_chars--;
|
||||
ret++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
|
||||
const uint16_t *in, size_t in_size)
|
||||
{
|
||||
static uint8_t kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
size_t out_pos = 0;
|
||||
size_t in_pos = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
unsigned numAdds;
|
||||
uint32_t value;
|
||||
|
||||
if (in_pos == in_size)
|
||||
{
|
||||
*out_chars = out_pos;
|
||||
return true;
|
||||
}
|
||||
value = in[in_pos++];
|
||||
if (value < 0x80)
|
||||
{
|
||||
if (out)
|
||||
out[out_pos] = (char)value;
|
||||
out_pos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value >= 0xD800 && value < 0xE000)
|
||||
{
|
||||
uint32_t c2;
|
||||
|
||||
if (value >= 0xDC00 || in_pos == in_size)
|
||||
break;
|
||||
c2 = in[in_pos++];
|
||||
if (c2 < 0xDC00 || c2 >= 0xE000)
|
||||
break;
|
||||
value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
|
||||
}
|
||||
|
||||
for (numAdds = 1; numAdds < 5; numAdds++)
|
||||
if (value < (((uint32_t)1) << (numAdds * 5 + 6)))
|
||||
break;
|
||||
if (out)
|
||||
out[out_pos] = (char)(kUtf8Limits[numAdds - 1]
|
||||
+ (value >> (6 * numAdds)));
|
||||
out_pos++;
|
||||
do
|
||||
{
|
||||
numAdds--;
|
||||
if (out)
|
||||
out[out_pos] = (char)(0x80
|
||||
+ ((value >> (6 * numAdds)) & 0x3F));
|
||||
out_pos++;
|
||||
}while (numAdds != 0);
|
||||
}
|
||||
|
||||
*out_chars = out_pos;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Acts mostly like strlcpy.
|
||||
*
|
||||
* Copies the given number of UTF-8 characters,
|
||||
* but at most d_len bytes.
|
||||
*
|
||||
* Always NULL terminates.
|
||||
* Does not copy half a character.
|
||||
*
|
||||
* Returns number of bytes. 's' is assumed valid UTF-8.
|
||||
* Use only if 'chars' is considerably less than 'd_len'. */
|
||||
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
|
||||
{
|
||||
const uint8_t *sb = (const uint8_t*)s;
|
||||
const uint8_t *sb_org = sb;
|
||||
|
||||
if (!s)
|
||||
return 0;
|
||||
|
||||
while (*sb && chars-- > 0)
|
||||
{
|
||||
sb++;
|
||||
while ((*sb & 0xC0) == 0x80) sb++;
|
||||
}
|
||||
|
||||
if ((size_t)(sb - sb_org) > d_len-1 /* NUL */)
|
||||
{
|
||||
sb = sb_org + d_len-1;
|
||||
while ((*sb & 0xC0) == 0x80) sb--;
|
||||
}
|
||||
|
||||
memcpy(d, sb_org, sb-sb_org);
|
||||
d[sb-sb_org] = '\0';
|
||||
|
||||
return sb-sb_org;
|
||||
}
|
||||
|
||||
const char *utf8skip(const char *str, size_t chars)
|
||||
{
|
||||
const uint8_t *strb = (const uint8_t*)str;
|
||||
if (!chars)
|
||||
return str;
|
||||
do
|
||||
{
|
||||
strb++;
|
||||
while ((*strb & 0xC0)==0x80) strb++;
|
||||
chars--;
|
||||
} while(chars);
|
||||
return (const char*)strb;
|
||||
}
|
||||
|
||||
size_t utf8len(const char *string)
|
||||
{
|
||||
size_t ret = 0;
|
||||
|
||||
if (!string)
|
||||
return 0;
|
||||
|
||||
while (*string)
|
||||
{
|
||||
if ((*string & 0xC0) != 0x80)
|
||||
ret++;
|
||||
string++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define utf8_walkbyte(string) (*((*(string))++))
|
||||
|
||||
/* Does not validate the input, returns garbage if it's not UTF-8. */
|
||||
uint32_t utf8_walk(const char **string)
|
||||
{
|
||||
uint8_t first = utf8_walkbyte(string);
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (first < 128)
|
||||
return first;
|
||||
|
||||
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
|
||||
if (first >= 0xE0)
|
||||
{
|
||||
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
|
||||
if (first >= 0xF0)
|
||||
{
|
||||
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
|
||||
return ret | (first & 7) << 18;
|
||||
}
|
||||
return ret | (first & 15) << 12;
|
||||
}
|
||||
|
||||
return ret | (first & 31) << 6;
|
||||
}
|
||||
|
||||
static bool utf16_to_char(uint8_t **utf_data,
|
||||
size_t *dest_len, const uint16_t *in)
|
||||
{
|
||||
unsigned len = 0;
|
||||
|
||||
while (in[len] != '\0')
|
||||
len++;
|
||||
|
||||
utf16_conv_utf8(NULL, dest_len, in, len);
|
||||
*dest_len += 1;
|
||||
*utf_data = (uint8_t*)malloc(*dest_len);
|
||||
if (*utf_data == 0)
|
||||
return false;
|
||||
|
||||
return utf16_conv_utf8(*utf_data, dest_len, in, len);
|
||||
}
|
||||
|
||||
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
|
||||
{
|
||||
size_t dest_len = 0;
|
||||
uint8_t *utf16_data = NULL;
|
||||
bool ret = utf16_to_char(&utf16_data, &dest_len, in);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
utf16_data[dest_len] = 0;
|
||||
strlcpy(s, (const char*)utf16_data, len);
|
||||
}
|
||||
|
||||
free(utf16_data);
|
||||
utf16_data = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
|
||||
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||
static char *mb_to_mb_string_alloc(const char *str,
|
||||
enum CodePage cp_in, enum CodePage cp_out)
|
||||
{
|
||||
char *path_buf = NULL;
|
||||
wchar_t *path_buf_wide = NULL;
|
||||
int path_buf_len = 0;
|
||||
int path_buf_wide_len = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0);
|
||||
|
||||
/* Windows 95 will return 0 from these functions with
|
||||
* a UTF8 codepage set without MSLU.
|
||||
*
|
||||
* From an unknown MSDN version (others omit this info):
|
||||
* - CP_UTF8 Windows 98/Me, Windows NT 4.0 and later:
|
||||
* Translate using UTF-8. When this is set, dwFlags must be zero.
|
||||
* - Windows 95: Under the Microsoft Layer for Unicode,
|
||||
* MultiByteToWideChar also supports CP_UTF7 and CP_UTF8.
|
||||
*/
|
||||
|
||||
if (path_buf_wide_len)
|
||||
{
|
||||
path_buf_wide = (wchar_t*)
|
||||
calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t));
|
||||
|
||||
if (path_buf_wide)
|
||||
{
|
||||
MultiByteToWideChar(cp_in, 0,
|
||||
str, -1, path_buf_wide, path_buf_wide_len);
|
||||
|
||||
if (*path_buf_wide)
|
||||
{
|
||||
path_buf_len = WideCharToMultiByte(cp_out, 0,
|
||||
path_buf_wide, -1, NULL, 0, NULL, NULL);
|
||||
|
||||
if (path_buf_len)
|
||||
{
|
||||
path_buf = (char*)
|
||||
calloc(path_buf_len + sizeof(char), sizeof(char));
|
||||
|
||||
if (path_buf)
|
||||
{
|
||||
WideCharToMultiByte(cp_out, 0,
|
||||
path_buf_wide, -1, path_buf,
|
||||
path_buf_len, NULL, NULL);
|
||||
|
||||
free(path_buf_wide);
|
||||
|
||||
if (*path_buf)
|
||||
return path_buf;
|
||||
|
||||
free(path_buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
free(path_buf_wide);
|
||||
return strdup(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
return strdup(str);
|
||||
|
||||
if (path_buf_wide)
|
||||
free(path_buf_wide);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||
char* utf8_to_local_string_alloc(const char *str)
|
||||
{
|
||||
if (str && *str)
|
||||
{
|
||||
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
|
||||
return mb_to_mb_string_alloc(str, CODEPAGE_UTF8, CODEPAGE_LOCAL);
|
||||
#else
|
||||
/* assume string needs no modification if not on Windows */
|
||||
return strdup(str);
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||
char* local_to_utf8_string_alloc(const char *str)
|
||||
{
|
||||
if (str && *str)
|
||||
{
|
||||
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
|
||||
return mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8);
|
||||
#else
|
||||
/* assume string needs no modification if not on Windows */
|
||||
return strdup(str);
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||
wchar_t* utf8_to_utf16_string_alloc(const char *str)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int len = 0;
|
||||
int out_len = 0;
|
||||
#else
|
||||
size_t len = 0;
|
||||
size_t out_len = 0;
|
||||
#endif
|
||||
wchar_t *buf = NULL;
|
||||
|
||||
if (!str || !*str)
|
||||
return NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
|
||||
|
||||
if (len)
|
||||
{
|
||||
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
out_len = MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* fallback to ANSI codepage instead */
|
||||
len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
|
||||
|
||||
if (len)
|
||||
{
|
||||
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
out_len = MultiByteToWideChar(CP_ACP, 0, str, -1, buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
if (out_len < 0)
|
||||
{
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
/* NOTE: For now, assume non-Windows platforms' locale is already UTF-8. */
|
||||
len = mbstowcs(NULL, str, 0) + 1;
|
||||
|
||||
if (len)
|
||||
{
|
||||
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
out_len = mbstowcs(buf, str, len);
|
||||
}
|
||||
|
||||
if (out_len == (size_t)-1)
|
||||
{
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||
char* utf16_to_utf8_string_alloc(const wchar_t *str)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int len = 0;
|
||||
#else
|
||||
size_t len = 0;
|
||||
#endif
|
||||
char *buf = NULL;
|
||||
|
||||
if (!str || !*str)
|
||||
return NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
{
|
||||
UINT code_page = CP_UTF8;
|
||||
len = WideCharToMultiByte(code_page,
|
||||
0, str, -1, NULL, 0, NULL, NULL);
|
||||
|
||||
/* fallback to ANSI codepage instead */
|
||||
if (!len)
|
||||
{
|
||||
code_page = CP_ACP;
|
||||
len = WideCharToMultiByte(code_page,
|
||||
0, str, -1, NULL, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
buf = (char*)calloc(len, sizeof(char));
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
if (WideCharToMultiByte(code_page,
|
||||
0, str, -1, buf, len, NULL, NULL) < 0)
|
||||
{
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* NOTE: For now, assume non-Windows platforms'
|
||||
* locale is already UTF-8. */
|
||||
len = wcstombs(NULL, str, 0) + 1;
|
||||
|
||||
if (len)
|
||||
{
|
||||
buf = (char*)calloc(len, sizeof(char));
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
if (wcstombs(buf, str, len) == (size_t)-1)
|
||||
{
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return buf;
|
||||
}
|
||||
889
lib/borealis/library/lib/extern/libretro-common/features/features_cpu.c
vendored
Normal file
889
lib/borealis/library/lib/extern/libretro-common/features/features_cpu.c
vendored
Normal file
@@ -0,0 +1,889 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (features_cpu.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <compat/strl.h>
|
||||
#include <streams/file_stream.h>
|
||||
#include <libretro.h>
|
||||
#include <features/features_cpu.h>
|
||||
#include <retro_timers.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(__CELLOS_LV2__)
|
||||
#ifndef _PPU_INTRINSICS_H
|
||||
#include <ppu_intrinsics.h>
|
||||
#endif
|
||||
#elif defined(_XBOX360)
|
||||
#include <PPCIntrinsics.h>
|
||||
#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(ANDROID) || defined(__QNX__) || defined(DJGPP)
|
||||
/* POSIX_MONOTONIC_CLOCK is not being defined in Android headers despite support being present. */
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if defined(__QNX__) && !defined(CLOCK_MONOTONIC)
|
||||
#define CLOCK_MONOTONIC 2
|
||||
#endif
|
||||
|
||||
#if defined(PSP)
|
||||
#include <pspkernel.h>
|
||||
#include <sys/time.h>
|
||||
#include <psprtc.h>
|
||||
#endif
|
||||
|
||||
#if defined(VITA)
|
||||
#include <psp2/kernel/processmgr.h>
|
||||
#include <psp2/rtc.h>
|
||||
#endif
|
||||
|
||||
#if defined(PS2)
|
||||
#include <kernel.h>
|
||||
#include <timer.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if defined(__PSL1GHT__)
|
||||
#include <sys/time.h>
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
#include <sys/sys_time.h>
|
||||
#endif
|
||||
|
||||
#ifdef GEKKO
|
||||
#include <ogc/lwp_watchdog.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIIU
|
||||
#include <wiiu/os/time.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LIBNX)
|
||||
#include <switch.h>
|
||||
#elif defined(SWITCH)
|
||||
#include <libtransistor/types.h>
|
||||
#include <libtransistor/svc.h>
|
||||
#endif
|
||||
|
||||
#if defined(_3DS)
|
||||
#include <3ds/svc.h>
|
||||
#include <3ds/os.h>
|
||||
#include <3ds/services/cfgu.h>
|
||||
#endif
|
||||
|
||||
/* iOS/OSX specific. Lacks clock_gettime(), so implement it. */
|
||||
#ifdef __MACH__
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifndef CLOCK_MONOTONIC
|
||||
#define CLOCK_MONOTONIC 0
|
||||
#endif
|
||||
|
||||
#ifndef CLOCK_REALTIME
|
||||
#define CLOCK_REALTIME 0
|
||||
#endif
|
||||
|
||||
/* this function is part of iOS 10 now */
|
||||
static int ra_clock_gettime(int clk_ik, struct timespec *t)
|
||||
{
|
||||
struct timeval now;
|
||||
int rv = gettimeofday(&now, NULL);
|
||||
if (rv)
|
||||
return rv;
|
||||
t->tv_sec = now.tv_sec;
|
||||
t->tv_nsec = now.tv_usec * 1000;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__MACH__) && __IPHONE_OS_VERSION_MIN_REQUIRED < 100000
|
||||
#else
|
||||
#define ra_clock_gettime clock_gettime
|
||||
#endif
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
#include <emscripten.h>
|
||||
#endif
|
||||
|
||||
#if defined(BSD) || defined(__APPLE__)
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* cpu_features_get_perf_counter:
|
||||
*
|
||||
* Gets performance counter.
|
||||
*
|
||||
* Returns: performance counter.
|
||||
**/
|
||||
retro_perf_tick_t cpu_features_get_perf_counter(void)
|
||||
{
|
||||
retro_perf_tick_t time_ticks = 0;
|
||||
#if defined(_WIN32)
|
||||
long tv_sec, tv_usec;
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1200
|
||||
static const unsigned __int64 epoch = 11644473600000000;
|
||||
#else
|
||||
static const unsigned __int64 epoch = 11644473600000000ULL;
|
||||
#endif
|
||||
FILETIME file_time;
|
||||
SYSTEMTIME system_time;
|
||||
ULARGE_INTEGER ularge;
|
||||
|
||||
GetSystemTime(&system_time);
|
||||
SystemTimeToFileTime(&system_time, &file_time);
|
||||
ularge.LowPart = file_time.dwLowDateTime;
|
||||
ularge.HighPart = file_time.dwHighDateTime;
|
||||
|
||||
tv_sec = (long)((ularge.QuadPart - epoch) / 10000000L);
|
||||
tv_usec = (long)(system_time.wMilliseconds * 1000);
|
||||
time_ticks = (1000000 * tv_sec + tv_usec);
|
||||
#elif defined(__linux__) || defined(__QNX__) || defined(__MACH__)
|
||||
struct timespec tv = {0};
|
||||
if (ra_clock_gettime(CLOCK_MONOTONIC, &tv) == 0)
|
||||
time_ticks = (retro_perf_tick_t)tv.tv_sec * 1000000000 +
|
||||
(retro_perf_tick_t)tv.tv_nsec;
|
||||
|
||||
#elif defined(__GNUC__) && defined(__i386__) || defined(__i486__) || defined(__i686__) || defined(_M_X64) || defined(_M_AMD64)
|
||||
__asm__ volatile ("rdtsc" : "=A" (time_ticks));
|
||||
#elif defined(__GNUC__) && defined(__x86_64__) || defined(_M_IX86)
|
||||
unsigned a, d;
|
||||
__asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
|
||||
time_ticks = (retro_perf_tick_t)a | ((retro_perf_tick_t)d << 32);
|
||||
#elif defined(__ARM_ARCH_6__)
|
||||
__asm__ volatile( "mrc p15, 0, %0, c9, c13, 0" : "=r"(time_ticks) );
|
||||
#elif defined(__CELLOS_LV2__) || defined(_XBOX360) || defined(__powerpc__) || defined(__ppc__) || defined(__POWERPC__)
|
||||
time_ticks = __mftb();
|
||||
#elif defined(GEKKO)
|
||||
time_ticks = gettime();
|
||||
#elif defined(PSP)
|
||||
sceRtcGetCurrentTick((uint64_t*)&time_ticks);
|
||||
#elif defined(VITA)
|
||||
sceRtcGetCurrentTick((SceRtcTick*)&time_ticks);
|
||||
#elif defined(PS2)
|
||||
time_ticks = clock()*294912; // 294,912MHZ / 1000 msecs
|
||||
#elif defined(_3DS)
|
||||
time_ticks = svcGetSystemTick();
|
||||
#elif defined(WIIU)
|
||||
time_ticks = OSGetSystemTime();
|
||||
#elif defined(__mips__)
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv,NULL);
|
||||
time_ticks = (1000000 * tv.tv_sec + tv.tv_usec);
|
||||
#elif defined(HAVE_LIBNX)
|
||||
time_ticks = armGetSystemTick();
|
||||
#endif
|
||||
|
||||
return time_ticks;
|
||||
}
|
||||
|
||||
/**
|
||||
* cpu_features_get_time_usec:
|
||||
*
|
||||
* Gets time in microseconds.
|
||||
*
|
||||
* Returns: time in microseconds.
|
||||
**/
|
||||
retro_time_t cpu_features_get_time_usec(void)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
static LARGE_INTEGER freq;
|
||||
LARGE_INTEGER count;
|
||||
|
||||
/* Frequency is guaranteed to not change. */
|
||||
if (!freq.QuadPart && !QueryPerformanceFrequency(&freq))
|
||||
return 0;
|
||||
|
||||
if (!QueryPerformanceCounter(&count))
|
||||
return 0;
|
||||
return count.QuadPart * 1000000 / freq.QuadPart;
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
return sys_time_get_system_time();
|
||||
#elif defined(GEKKO)
|
||||
return ticks_to_microsecs(gettime());
|
||||
#elif defined(WIIU)
|
||||
return ticks_to_us(OSGetSystemTime());
|
||||
#elif defined(SWITCH) || defined(HAVE_LIBNX)
|
||||
return (svcGetSystemTick() * 10) / 192;
|
||||
#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(__QNX__) || defined(ANDROID) || defined(__MACH__)
|
||||
struct timespec tv = {0};
|
||||
if (ra_clock_gettime(CLOCK_MONOTONIC, &tv) < 0)
|
||||
return 0;
|
||||
return tv.tv_sec * INT64_C(1000000) + (tv.tv_nsec + 500) / 1000;
|
||||
#elif defined(EMSCRIPTEN)
|
||||
return emscripten_get_now() * 1000;
|
||||
#elif defined(PS2)
|
||||
return clock()*1000;
|
||||
#elif defined(__mips__) || defined(DJGPP)
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv,NULL);
|
||||
return (1000000 * tv.tv_sec + tv.tv_usec);
|
||||
#elif defined(_3DS)
|
||||
return osGetTime() * 1000;
|
||||
#elif defined(VITA)
|
||||
return sceKernelGetProcessTimeWide();
|
||||
#else
|
||||
#error "Your platform does not have a timer function implemented in cpu_features_get_time_usec(). Cannot continue."
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__) || defined(__i486__) || defined(__i686__) || (defined(_M_X64) && _MSC_VER > 1310) || (defined(_M_IX86) && _MSC_VER > 1310)
|
||||
#define CPU_X86
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_XBOX)
|
||||
#if (_MSC_VER > 1310)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CPU_X86) && !defined(__MACH__)
|
||||
void x86_cpuid(int func, int flags[4])
|
||||
{
|
||||
/* On Android, we compile RetroArch with PIC, and we
|
||||
* are not allowed to clobber the ebx register. */
|
||||
#ifdef __x86_64__
|
||||
#define REG_b "rbx"
|
||||
#define REG_S "rsi"
|
||||
#else
|
||||
#define REG_b "ebx"
|
||||
#define REG_S "esi"
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
__asm__ volatile (
|
||||
"mov %%" REG_b ", %%" REG_S "\n"
|
||||
"cpuid\n"
|
||||
"xchg %%" REG_b ", %%" REG_S "\n"
|
||||
: "=a"(flags[0]), "=S"(flags[1]), "=c"(flags[2]), "=d"(flags[3])
|
||||
: "a"(func));
|
||||
#elif defined(_MSC_VER)
|
||||
__cpuid(flags, func);
|
||||
#else
|
||||
printf("Unknown compiler. Cannot check CPUID with inline assembly.\n");
|
||||
memset(flags, 0, 4 * sizeof(int));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Only runs on i686 and above. Needs to be conditionally run. */
|
||||
static uint64_t xgetbv_x86(uint32_t idx)
|
||||
{
|
||||
#if defined(__GNUC__)
|
||||
uint32_t eax, edx;
|
||||
__asm__ volatile (
|
||||
/* Older GCC versions (Apple's GCC for example) do
|
||||
* not understand xgetbv instruction.
|
||||
* Stamp out the machine code directly.
|
||||
*/
|
||||
".byte 0x0f, 0x01, 0xd0\n"
|
||||
: "=a"(eax), "=d"(edx) : "c"(idx));
|
||||
return ((uint64_t)edx << 32) | eax;
|
||||
#elif _MSC_FULL_VER >= 160040219
|
||||
/* Intrinsic only works on 2010 SP1 and above. */
|
||||
return _xgetbv(idx);
|
||||
#else
|
||||
printf("Unknown compiler. Cannot check xgetbv bits.\n");
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_NEON__)
|
||||
static void arm_enable_runfast_mode(void)
|
||||
{
|
||||
/* RunFast mode. Enables flush-to-zero and some
|
||||
* floating point optimizations. */
|
||||
static const unsigned x = 0x04086060;
|
||||
static const unsigned y = 0x03000000;
|
||||
int r;
|
||||
__asm__ volatile(
|
||||
"fmrx %0, fpscr \n\t" /* r0 = FPSCR */
|
||||
"and %0, %0, %1 \n\t" /* r0 = r0 & 0x04086060 */
|
||||
"orr %0, %0, %2 \n\t" /* r0 = r0 | 0x03000000 */
|
||||
"fmxr fpscr, %0 \n\t" /* FPSCR = r0 */
|
||||
: "=r"(r)
|
||||
: "r"(x), "r"(y)
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && !defined(CPU_X86)
|
||||
static unsigned char check_arm_cpu_feature(const char* feature)
|
||||
{
|
||||
char line[1024];
|
||||
unsigned char status = 0;
|
||||
RFILE *fp = filestream_open("/proc/cpuinfo",
|
||||
RETRO_VFS_FILE_ACCESS_READ,
|
||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||
|
||||
if (!fp)
|
||||
return 0;
|
||||
|
||||
while (filestream_gets(fp, line, sizeof(line)) != NULL)
|
||||
{
|
||||
if (strncmp(line, "Features\t: ", 11))
|
||||
continue;
|
||||
|
||||
if (strstr(line + 11, feature) != NULL)
|
||||
status = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
filestream_close(fp);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#if !defined(_SC_NPROCESSORS_ONLN)
|
||||
/* Parse an decimal integer starting from 'input', but not going further
|
||||
* than 'limit'. Return the value into '*result'.
|
||||
*
|
||||
* NOTE: Does not skip over leading spaces, or deal with sign characters.
|
||||
* NOTE: Ignores overflows.
|
||||
*
|
||||
* The function returns NULL in case of error (bad format), or the new
|
||||
* position after the decimal number in case of success (which will always
|
||||
* be <= 'limit').
|
||||
*/
|
||||
static const char *parse_decimal(const char* input,
|
||||
const char* limit, int* result)
|
||||
{
|
||||
const char* p = input;
|
||||
int val = 0;
|
||||
|
||||
while (p < limit)
|
||||
{
|
||||
int d = (*p - '0');
|
||||
if ((unsigned)d >= 10U)
|
||||
break;
|
||||
val = val*10 + d;
|
||||
p++;
|
||||
}
|
||||
if (p == input)
|
||||
return NULL;
|
||||
|
||||
*result = val;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Parse a textual list of cpus and store the result inside a CpuList object.
|
||||
* Input format is the following:
|
||||
* - comma-separated list of items (no spaces)
|
||||
* - each item is either a single decimal number (cpu index), or a range made
|
||||
* of two numbers separated by a single dash (-). Ranges are inclusive.
|
||||
*
|
||||
* Examples: 0
|
||||
* 2,4-127,128-143
|
||||
* 0-1
|
||||
*/
|
||||
static void cpulist_parse(CpuList* list, char **buf, ssize_t length)
|
||||
{
|
||||
const char* p = (const char*)buf;
|
||||
const char* end = p + length;
|
||||
|
||||
/* NOTE: the input line coming from sysfs typically contains a
|
||||
* trailing newline, so take care of it in the code below
|
||||
*/
|
||||
while (p < end && *p != '\n')
|
||||
{
|
||||
int val, start_value, end_value;
|
||||
/* Find the end of current item, and put it into 'q' */
|
||||
const char *q = (const char*)memchr(p, ',', end-p);
|
||||
|
||||
if (!q)
|
||||
q = end;
|
||||
|
||||
/* Get first value */
|
||||
p = parse_decimal(p, q, &start_value);
|
||||
if (p == NULL)
|
||||
return;
|
||||
|
||||
end_value = start_value;
|
||||
|
||||
/* If we're not at the end of the item, expect a dash and
|
||||
* and integer; extract end value.
|
||||
*/
|
||||
if (p < q && *p == '-')
|
||||
{
|
||||
p = parse_decimal(p+1, q, &end_value);
|
||||
if (p == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set bits CPU list bits */
|
||||
for (val = start_value; val <= end_value; val++)
|
||||
{
|
||||
if ((unsigned)val < 32)
|
||||
list->mask |= (uint32_t)(1U << val);
|
||||
}
|
||||
|
||||
/* Jump to next item */
|
||||
p = q;
|
||||
if (p < end)
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read a CPU list from one sysfs file */
|
||||
static void cpulist_read_from(CpuList* list, const char* filename)
|
||||
{
|
||||
ssize_t length;
|
||||
char *buf = NULL;
|
||||
|
||||
list->mask = 0;
|
||||
|
||||
if (filestream_read_file(filename, (void**)&buf, &length) != 1)
|
||||
return;
|
||||
|
||||
cpulist_parse(list, &buf, length);
|
||||
if (buf)
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* cpu_features_get_core_amount:
|
||||
*
|
||||
* Gets the amount of available CPU cores.
|
||||
*
|
||||
* Returns: amount of CPU cores available.
|
||||
**/
|
||||
unsigned cpu_features_get_core_amount(void)
|
||||
{
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
/* Win32 */
|
||||
SYSTEM_INFO sysinfo;
|
||||
#if defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
|
||||
GetNativeSystemInfo(&sysinfo);
|
||||
#else
|
||||
GetSystemInfo(&sysinfo);
|
||||
#endif
|
||||
return sysinfo.dwNumberOfProcessors;
|
||||
#elif defined(GEKKO)
|
||||
return 1;
|
||||
#elif defined(PSP) || defined(PS2)
|
||||
return 1;
|
||||
#elif defined(VITA)
|
||||
return 4;
|
||||
#elif defined(HAVE_LIBNX) || defined(SWITCH)
|
||||
return 4;
|
||||
#elif defined(_3DS)
|
||||
u8 device_model = 0xFF;
|
||||
CFGU_GetSystemModel(&device_model);/*(0 = O3DS, 1 = O3DSXL, 2 = N3DS, 3 = 2DS, 4 = N3DSXL, 5 = N2DSXL)*/
|
||||
switch (device_model)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 3:
|
||||
/*Old 3/2DS*/
|
||||
return 2;
|
||||
|
||||
case 2:
|
||||
case 4:
|
||||
case 5:
|
||||
/*New 3/2DS*/
|
||||
return 4;
|
||||
|
||||
default:
|
||||
/*Unknown Device Or Check Failed*/
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
#elif defined(WIIU)
|
||||
return 3;
|
||||
#elif defined(_SC_NPROCESSORS_ONLN)
|
||||
/* Linux, most UNIX-likes. */
|
||||
long ret = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
if (ret <= 0)
|
||||
return (unsigned)1;
|
||||
return (unsigned)ret;
|
||||
#elif defined(BSD) || defined(__APPLE__)
|
||||
/* BSD */
|
||||
/* Copypasta from stackoverflow, dunno if it works. */
|
||||
int num_cpu = 0;
|
||||
int mib[4];
|
||||
size_t len = sizeof(num_cpu);
|
||||
|
||||
mib[0] = CTL_HW;
|
||||
mib[1] = HW_AVAILCPU;
|
||||
sysctl(mib, 2, &num_cpu, &len, NULL, 0);
|
||||
if (num_cpu < 1)
|
||||
{
|
||||
mib[1] = HW_NCPU;
|
||||
sysctl(mib, 2, &num_cpu, &len, NULL, 0);
|
||||
if (num_cpu < 1)
|
||||
num_cpu = 1;
|
||||
}
|
||||
return num_cpu;
|
||||
#elif defined(__linux__)
|
||||
CpuList cpus_present[1];
|
||||
CpuList cpus_possible[1];
|
||||
int amount = 0;
|
||||
|
||||
cpulist_read_from(cpus_present, "/sys/devices/system/cpu/present");
|
||||
cpulist_read_from(cpus_possible, "/sys/devices/system/cpu/possible");
|
||||
|
||||
/* Compute the intersection of both sets to get the actual number of
|
||||
* CPU cores that can be used on this device by the kernel.
|
||||
*/
|
||||
cpus_present->mask &= cpus_possible->mask;
|
||||
amount = __builtin_popcount(cpus_present->mask);
|
||||
|
||||
if (amount == 0)
|
||||
return 1;
|
||||
return amount;
|
||||
#elif defined(_XBOX360)
|
||||
return 3;
|
||||
#else
|
||||
/* No idea, assume single core. */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* According to http://en.wikipedia.org/wiki/CPUID */
|
||||
#define VENDOR_INTEL_b 0x756e6547
|
||||
#define VENDOR_INTEL_c 0x6c65746e
|
||||
#define VENDOR_INTEL_d 0x49656e69
|
||||
|
||||
/**
|
||||
* cpu_features_get:
|
||||
*
|
||||
* Gets CPU features..
|
||||
*
|
||||
* Returns: bitmask of all CPU features available.
|
||||
**/
|
||||
uint64_t cpu_features_get(void)
|
||||
{
|
||||
int flags[4];
|
||||
int vendor_shuffle[3];
|
||||
char vendor[13];
|
||||
size_t len = 0;
|
||||
uint64_t cpu_flags = 0;
|
||||
uint64_t cpu = 0;
|
||||
unsigned max_flag = 0;
|
||||
#if defined(CPU_X86) && !defined(__MACH__)
|
||||
int vendor_is_intel = 0;
|
||||
const int avx_flags = (1 << 27) | (1 << 28);
|
||||
#endif
|
||||
|
||||
char buf[sizeof(" MMX MMXEXT SSE SSE2 SSE3 SSSE3 SS4 SSE4.2 AES AVX AVX2 NEON VMX VMX128 VFPU PS")];
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
(void)len;
|
||||
(void)cpu_flags;
|
||||
(void)flags;
|
||||
(void)max_flag;
|
||||
(void)vendor;
|
||||
(void)vendor_shuffle;
|
||||
|
||||
#if defined(__MACH__)
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.mmx", NULL, &len, NULL, 0) == 0)
|
||||
{
|
||||
cpu |= RETRO_SIMD_MMX;
|
||||
cpu |= RETRO_SIMD_MMXEXT;
|
||||
}
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.floatingpoint", NULL, &len, NULL, 0) == 0)
|
||||
{
|
||||
cpu |= RETRO_SIMD_CMOV;
|
||||
}
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.sse", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_SSE;
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.sse2", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_SSE2;
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.sse3", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_SSE3;
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.supplementalsse3", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_SSSE3;
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.sse4_1", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_SSE4;
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.sse4_2", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_SSE42;
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.aes", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_AES;
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.avx1_0", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_AVX;
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.avx2_0", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_AVX2;
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.altivec", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_VMX;
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.neon", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_NEON;
|
||||
|
||||
#elif defined(_XBOX1)
|
||||
cpu |= RETRO_SIMD_MMX;
|
||||
cpu |= RETRO_SIMD_SSE;
|
||||
cpu |= RETRO_SIMD_MMXEXT;
|
||||
#elif defined(CPU_X86)
|
||||
(void)avx_flags;
|
||||
|
||||
x86_cpuid(0, flags);
|
||||
vendor_shuffle[0] = flags[1];
|
||||
vendor_shuffle[1] = flags[3];
|
||||
vendor_shuffle[2] = flags[2];
|
||||
|
||||
vendor[0] = '\0';
|
||||
memcpy(vendor, vendor_shuffle, sizeof(vendor_shuffle));
|
||||
|
||||
/* printf("[CPUID]: Vendor: %s\n", vendor); */
|
||||
|
||||
vendor_is_intel = (
|
||||
flags[1] == VENDOR_INTEL_b &&
|
||||
flags[2] == VENDOR_INTEL_c &&
|
||||
flags[3] == VENDOR_INTEL_d);
|
||||
|
||||
max_flag = flags[0];
|
||||
if (max_flag < 1) /* Does CPUID not support func = 1? (unlikely ...) */
|
||||
return 0;
|
||||
|
||||
x86_cpuid(1, flags);
|
||||
|
||||
if (flags[3] & (1 << 15))
|
||||
cpu |= RETRO_SIMD_CMOV;
|
||||
|
||||
if (flags[3] & (1 << 23))
|
||||
cpu |= RETRO_SIMD_MMX;
|
||||
|
||||
if (flags[3] & (1 << 25))
|
||||
{
|
||||
/* SSE also implies MMXEXT (according to FFmpeg source). */
|
||||
cpu |= RETRO_SIMD_SSE;
|
||||
cpu |= RETRO_SIMD_MMXEXT;
|
||||
}
|
||||
|
||||
if (flags[3] & (1 << 26))
|
||||
cpu |= RETRO_SIMD_SSE2;
|
||||
|
||||
if (flags[2] & (1 << 0))
|
||||
cpu |= RETRO_SIMD_SSE3;
|
||||
|
||||
if (flags[2] & (1 << 9))
|
||||
cpu |= RETRO_SIMD_SSSE3;
|
||||
|
||||
if (flags[2] & (1 << 19))
|
||||
cpu |= RETRO_SIMD_SSE4;
|
||||
|
||||
if (flags[2] & (1 << 20))
|
||||
cpu |= RETRO_SIMD_SSE42;
|
||||
|
||||
if ((flags[2] & (1 << 23)))
|
||||
cpu |= RETRO_SIMD_POPCNT;
|
||||
|
||||
if (vendor_is_intel && (flags[2] & (1 << 22)))
|
||||
cpu |= RETRO_SIMD_MOVBE;
|
||||
|
||||
if (flags[2] & (1 << 25))
|
||||
cpu |= RETRO_SIMD_AES;
|
||||
|
||||
/* Must only perform xgetbv check if we have
|
||||
* AVX CPU support (guaranteed to have at least i686). */
|
||||
if (((flags[2] & avx_flags) == avx_flags)
|
||||
&& ((xgetbv_x86(0) & 0x6) == 0x6))
|
||||
cpu |= RETRO_SIMD_AVX;
|
||||
|
||||
if (max_flag >= 7)
|
||||
{
|
||||
x86_cpuid(7, flags);
|
||||
if (flags[1] & (1 << 5))
|
||||
cpu |= RETRO_SIMD_AVX2;
|
||||
}
|
||||
|
||||
x86_cpuid(0x80000000, flags);
|
||||
max_flag = flags[0];
|
||||
if (max_flag >= 0x80000001u)
|
||||
{
|
||||
x86_cpuid(0x80000001, flags);
|
||||
if (flags[3] & (1 << 23))
|
||||
cpu |= RETRO_SIMD_MMX;
|
||||
if (flags[3] & (1 << 22))
|
||||
cpu |= RETRO_SIMD_MMXEXT;
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
if (check_arm_cpu_feature("neon"))
|
||||
{
|
||||
cpu |= RETRO_SIMD_NEON;
|
||||
#ifdef __ARM_NEON__
|
||||
arm_enable_runfast_mode();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (check_arm_cpu_feature("vfpv3"))
|
||||
cpu |= RETRO_SIMD_VFPV3;
|
||||
|
||||
if (check_arm_cpu_feature("vfpv4"))
|
||||
cpu |= RETRO_SIMD_VFPV4;
|
||||
|
||||
if (check_arm_cpu_feature("asimd"))
|
||||
{
|
||||
cpu |= RETRO_SIMD_ASIMD;
|
||||
#ifdef __ARM_NEON__
|
||||
cpu |= RETRO_SIMD_NEON;
|
||||
arm_enable_runfast_mode();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
check_arm_cpu_feature("swp");
|
||||
check_arm_cpu_feature("half");
|
||||
check_arm_cpu_feature("thumb");
|
||||
check_arm_cpu_feature("fastmult");
|
||||
check_arm_cpu_feature("vfp");
|
||||
check_arm_cpu_feature("edsp");
|
||||
check_arm_cpu_feature("thumbee");
|
||||
check_arm_cpu_feature("tls");
|
||||
check_arm_cpu_feature("idiva");
|
||||
check_arm_cpu_feature("idivt");
|
||||
#endif
|
||||
|
||||
#elif defined(__ARM_NEON__)
|
||||
cpu |= RETRO_SIMD_NEON;
|
||||
arm_enable_runfast_mode();
|
||||
#elif defined(__ALTIVEC__)
|
||||
cpu |= RETRO_SIMD_VMX;
|
||||
#elif defined(XBOX360)
|
||||
cpu |= RETRO_SIMD_VMX128;
|
||||
#elif defined(PSP) || defined(PS2)
|
||||
cpu |= RETRO_SIMD_VFPU;
|
||||
#elif defined(GEKKO)
|
||||
cpu |= RETRO_SIMD_PS;
|
||||
#endif
|
||||
|
||||
if (cpu & RETRO_SIMD_MMX) strlcat(buf, " MMX", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_MMXEXT) strlcat(buf, " MMXEXT", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_SSE) strlcat(buf, " SSE", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_SSE2) strlcat(buf, " SSE2", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_SSE3) strlcat(buf, " SSE3", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_SSSE3) strlcat(buf, " SSSE3", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_SSE4) strlcat(buf, " SSE4", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_SSE42) strlcat(buf, " SSE4.2", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_AES) strlcat(buf, " AES", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_AVX) strlcat(buf, " AVX", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_AVX2) strlcat(buf, " AVX2", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_NEON) strlcat(buf, " NEON", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_VFPV3) strlcat(buf, " VFPv3", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_VFPV4) strlcat(buf, " VFPv4", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_VMX) strlcat(buf, " VMX", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_VMX128) strlcat(buf, " VMX128", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_VFPU) strlcat(buf, " VFPU", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_PS) strlcat(buf, " PS", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_ASIMD) strlcat(buf, " ASIMD", sizeof(buf));
|
||||
|
||||
return cpu;
|
||||
}
|
||||
|
||||
void cpu_features_get_model_name(char *name, int len)
|
||||
{
|
||||
#if defined(CPU_X86) && !defined(__MACH__)
|
||||
union {
|
||||
int i[4];
|
||||
unsigned char s[16];
|
||||
} flags;
|
||||
int i, j;
|
||||
size_t pos = 0;
|
||||
bool start = false;
|
||||
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
x86_cpuid(0x80000000, flags.i);
|
||||
|
||||
if (flags.i[0] < 0x80000004)
|
||||
return;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
memset(flags.i, 0, sizeof(flags.i));
|
||||
x86_cpuid(0x80000002 + i, flags.i);
|
||||
|
||||
for (j = 0; j < sizeof(flags.s); j++)
|
||||
{
|
||||
if (!start && flags.s[j] == ' ')
|
||||
continue;
|
||||
else
|
||||
start = true;
|
||||
|
||||
if (pos == len - 1)
|
||||
{
|
||||
/* truncate if we ran out of room */
|
||||
name[pos] = '\0';
|
||||
goto end;
|
||||
}
|
||||
|
||||
name[pos++] = flags.s[j];
|
||||
}
|
||||
}
|
||||
end:
|
||||
/* terminate our string */
|
||||
if (pos < (size_t)len)
|
||||
name[pos] = '\0';
|
||||
#elif defined(__MACH__)
|
||||
if (!name)
|
||||
return;
|
||||
{
|
||||
size_t len_size = len;
|
||||
sysctlbyname("machdep.cpu.brand_string", name, &len_size, NULL, 0);
|
||||
}
|
||||
#else
|
||||
if (!name)
|
||||
return;
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
18
lib/borealis/library/lib/extern/nanovg/LICENSE.txt
vendored
Normal file
18
lib/borealis/library/lib/extern/nanovg/LICENSE.txt
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
Copyright (c) 2013 Mikko Mononen memon@inside.org
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
2906
lib/borealis/library/lib/extern/nanovg/nanovg.c
vendored
Normal file
2906
lib/borealis/library/lib/extern/nanovg/nanovg.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
74
lib/borealis/library/lib/header.cpp
Normal file
74
lib/borealis/library/lib/header.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <borealis/application.hpp>
|
||||
#include <borealis/header.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
Header::Header(std::string label, bool separator, std::string sublabel)
|
||||
: label(label)
|
||||
, sublabel(sublabel)
|
||||
, separator(separator)
|
||||
{
|
||||
Style* style = Application::getStyle();
|
||||
this->setHeight(style->Header.height);
|
||||
}
|
||||
|
||||
void Header::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx)
|
||||
{
|
||||
unsigned padding = style->Header.padding;
|
||||
|
||||
// Rectangle
|
||||
nvgBeginPath(vg);
|
||||
nvgFillColor(vg, a(ctx->theme->headerRectangleColor));
|
||||
nvgRect(vg, x, y + padding, style->Header.rectangleWidth, height - padding * 2);
|
||||
nvgFill(vg);
|
||||
|
||||
// Label
|
||||
nvgBeginPath(vg);
|
||||
nvgFontFaceId(vg, ctx->fontStash->regular);
|
||||
nvgFontSize(vg, style->Header.fontSize);
|
||||
nvgFillColor(vg, a(ctx->theme->textColor));
|
||||
nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
|
||||
nvgText(vg, x + style->Header.rectangleWidth + padding, y + height / 2, this->label.c_str(), nullptr);
|
||||
|
||||
// Sublabel
|
||||
if (this->sublabel != "")
|
||||
{
|
||||
nvgBeginPath(vg);
|
||||
nvgFontFaceId(vg, ctx->fontStash->regular);
|
||||
nvgFontSize(vg, style->Header.fontSize);
|
||||
nvgFillColor(vg, a(ctx->theme->descriptionColor));
|
||||
nvgTextAlign(vg, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE);
|
||||
nvgText(vg, x + width - style->Header.rectangleWidth - padding, y + height / 2, this->sublabel.c_str(), nullptr);
|
||||
}
|
||||
|
||||
// Separator
|
||||
if (this->separator)
|
||||
{
|
||||
nvgBeginPath(vg);
|
||||
nvgFillColor(vg, a(ctx->theme->listItemSeparatorColor));
|
||||
nvgRect(vg, x, y + height, width, 1);
|
||||
nvgFill(vg);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace brls
|
||||
224
lib/borealis/library/lib/hint.cpp
Normal file
224
lib/borealis/library/lib/hint.cpp
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2020 WerWolv
|
||||
Copyright (C) 2020 natinusala
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <borealis/actions.hpp>
|
||||
#include <borealis/application.hpp>
|
||||
#include <borealis/hint.hpp>
|
||||
#include <borealis/label.hpp>
|
||||
#include <set>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
Hint::Hint(bool animate)
|
||||
: BoxLayout(BoxLayoutOrientation::HORIZONTAL)
|
||||
, animate(animate)
|
||||
{
|
||||
Style* style = Application::getStyle();
|
||||
|
||||
this->setGravity(BoxLayoutGravity::RIGHT);
|
||||
this->setHeight(style->AppletFrame.footerHeight);
|
||||
this->setSpacing(style->AppletFrame.footerTextSpacing);
|
||||
|
||||
// Subscribe to all events
|
||||
this->globalFocusEventSubscriptor = Application::getGlobalFocusChangeEvent()->subscribe([this](View* newFocus) {
|
||||
this->rebuildHints();
|
||||
});
|
||||
|
||||
this->globalHintsUpdateEventSubscriptor = Application::getGlobalHintsUpdateEvent()->subscribe([this]() {
|
||||
this->rebuildHints();
|
||||
});
|
||||
}
|
||||
|
||||
bool actionsSortFunc(Action a, Action b)
|
||||
{
|
||||
// From left to right:
|
||||
// - first +
|
||||
// - then all hints that are not B and A
|
||||
// - finally B and A
|
||||
|
||||
// + is before all others
|
||||
if (a.key == Key::PLUS)
|
||||
return true;
|
||||
|
||||
// A is after all others
|
||||
if (b.key == Key::A)
|
||||
return true;
|
||||
|
||||
// B is after all others but A
|
||||
if (b.key == Key::B && a.key != Key::A)
|
||||
return true;
|
||||
|
||||
// Keep original order for the rest
|
||||
return false;
|
||||
}
|
||||
|
||||
void Hint::rebuildHints()
|
||||
{
|
||||
// Check if the focused element is still a child of the same parent as the hint view's
|
||||
{
|
||||
View* focusParent = Application::getCurrentFocus();
|
||||
View* hintBaseParent = this;
|
||||
|
||||
while (focusParent != nullptr)
|
||||
{
|
||||
if (focusParent->getParent() == nullptr)
|
||||
break;
|
||||
focusParent = focusParent->getParent();
|
||||
}
|
||||
|
||||
while (hintBaseParent != nullptr)
|
||||
{
|
||||
if (hintBaseParent->getParent() == nullptr)
|
||||
break;
|
||||
hintBaseParent = hintBaseParent->getParent();
|
||||
}
|
||||
|
||||
if (focusParent != hintBaseParent)
|
||||
return;
|
||||
}
|
||||
|
||||
// Empty the layout and re-populate it with new Labels
|
||||
this->clear(true);
|
||||
|
||||
std::set<Key> addedKeys; // we only ever want one action per key
|
||||
View* focusParent = Application::getCurrentFocus();
|
||||
|
||||
// Iterate over the view tree to find all the actions to display
|
||||
std::vector<Action> actions;
|
||||
|
||||
while (focusParent != nullptr)
|
||||
{
|
||||
for (auto& action : focusParent->getActions())
|
||||
{
|
||||
if (action.hidden)
|
||||
continue;
|
||||
|
||||
if (addedKeys.find(action.key) != addedKeys.end())
|
||||
continue;
|
||||
|
||||
addedKeys.insert(action.key);
|
||||
actions.push_back(action);
|
||||
}
|
||||
|
||||
focusParent = focusParent->getParent();
|
||||
}
|
||||
|
||||
// Sort the actions
|
||||
std::stable_sort(actions.begin(), actions.end(), actionsSortFunc);
|
||||
|
||||
// Populate the layout with labels
|
||||
for (Action action : actions)
|
||||
{
|
||||
std::string hintText = Hint::getKeyIcon(action.key) + " " + action.hintText;
|
||||
|
||||
Label* label = new Label(LabelStyle::HINT, hintText);
|
||||
this->addView(label);
|
||||
}
|
||||
}
|
||||
|
||||
Hint::~Hint()
|
||||
{
|
||||
// Unregister all events
|
||||
Application::getGlobalFocusChangeEvent()->unsubscribe(this->globalFocusEventSubscriptor);
|
||||
Application::getGlobalHintsUpdateEvent()->unsubscribe(this->globalHintsUpdateEventSubscriptor);
|
||||
}
|
||||
|
||||
std::string Hint::getKeyIcon(Key key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case Key::A:
|
||||
return "\uE0E0";
|
||||
case Key::B:
|
||||
return "\uE0E1";
|
||||
case Key::X:
|
||||
return "\uE0E2";
|
||||
case Key::Y:
|
||||
return "\uE0E3";
|
||||
case Key::LSTICK:
|
||||
return "\uE104";
|
||||
case Key::RSTICK:
|
||||
return "\uE105";
|
||||
case Key::L:
|
||||
return "\uE0E4";
|
||||
case Key::R:
|
||||
return "\uE0E5";
|
||||
case Key::PLUS:
|
||||
return "\uE0EF";
|
||||
case Key::MINUS:
|
||||
return "\uE0F0";
|
||||
case Key::DLEFT:
|
||||
return "\uE0ED";
|
||||
case Key::DUP:
|
||||
return "\uE0EB";
|
||||
case Key::DRIGHT:
|
||||
return "\uE0EF";
|
||||
case Key::DDOWN:
|
||||
return "\uE0EC";
|
||||
default:
|
||||
return "\uE152";
|
||||
}
|
||||
}
|
||||
|
||||
void Hint::willAppear(bool resetState)
|
||||
{
|
||||
// Push ourself to hide other hints
|
||||
// We assume that we are the top-most hint
|
||||
Hint::pushHint(this);
|
||||
}
|
||||
|
||||
void Hint::willDisappear(bool resetState)
|
||||
{
|
||||
// Pop ourself to show other hints
|
||||
Hint::popHint(this);
|
||||
}
|
||||
|
||||
void Hint::pushHint(Hint* hint)
|
||||
{
|
||||
// If the hint is already in the stack, remove it and put it back on top
|
||||
Hint::globalHintStack.erase(std::remove(Hint::globalHintStack.begin(), Hint::globalHintStack.end(), hint), Hint::globalHintStack.end());
|
||||
Hint::globalHintStack.push_back(hint);
|
||||
|
||||
//Trigger animation
|
||||
Hint::animateHints();
|
||||
}
|
||||
|
||||
void Hint::popHint(Hint* hint)
|
||||
{
|
||||
Hint::globalHintStack.erase(std::remove(Hint::globalHintStack.begin(), Hint::globalHintStack.end(), hint), Hint::globalHintStack.end());
|
||||
Hint::animateHints();
|
||||
|
||||
// animateHints() won't call hide() on the hint since it's been removed from the stack
|
||||
// but it doesn't matter since it is getting destroyed anyay
|
||||
}
|
||||
|
||||
void Hint::animateHints()
|
||||
{
|
||||
for (size_t i = 0; i < Hint::globalHintStack.size(); i++)
|
||||
{
|
||||
// Last one = top one: show
|
||||
if (i == Hint::globalHintStack.size() - 1)
|
||||
Hint::globalHintStack[i]->show([]() {}, false);
|
||||
else
|
||||
Hint::globalHintStack[i]->hide([]() {}, false);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace brls
|
||||
183
lib/borealis/library/lib/image.cpp
Normal file
183
lib/borealis/library/lib/image.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 WerWolv
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <borealis/application.hpp>
|
||||
#include <borealis/image.hpp>
|
||||
#include <cstring>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
Image::Image(std::string imagePath)
|
||||
{
|
||||
this->setImage(imagePath);
|
||||
this->setOpacity(1.0F);
|
||||
}
|
||||
|
||||
Image::Image(unsigned char* buffer, size_t bufferSize)
|
||||
{
|
||||
this->setImage(buffer, bufferSize);
|
||||
this->setOpacity(1.0F);
|
||||
}
|
||||
|
||||
Image::~Image()
|
||||
{
|
||||
if (this->imageBuffer != nullptr)
|
||||
delete[] this->imageBuffer;
|
||||
|
||||
if (this->texture != -1)
|
||||
nvgDeleteImage(Application::getNVGContext(), this->texture);
|
||||
}
|
||||
|
||||
void Image::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx)
|
||||
{
|
||||
nvgSave(vg);
|
||||
|
||||
if (this->texture != -1)
|
||||
{
|
||||
nvgBeginPath(vg);
|
||||
nvgRoundedRect(vg, x + this->imageX, y + this->imageY, this->imageWidth, this->imageHeight, this->cornerRadius);
|
||||
nvgFillPaint(vg, a(this->imgPaint));
|
||||
nvgFill(vg);
|
||||
}
|
||||
|
||||
nvgRestore(vg);
|
||||
}
|
||||
|
||||
void Image::reloadTexture()
|
||||
{
|
||||
NVGcontext* vg = Application::getNVGContext();
|
||||
|
||||
if (this->texture != -1)
|
||||
nvgDeleteImage(vg, this->texture);
|
||||
|
||||
if (!this->imagePath.empty())
|
||||
this->texture = nvgCreateImage(vg, this->imagePath.c_str(), 0);
|
||||
else if (this->imageBuffer != nullptr)
|
||||
this->texture = nvgCreateImageMem(vg, 0, this->imageBuffer, this->imageBufferSize);
|
||||
}
|
||||
|
||||
void Image::layout(NVGcontext* vg, Style* style, FontStash* stash)
|
||||
{
|
||||
if (this->origViewWidth == 0 || this->origViewHeight == 0)
|
||||
{
|
||||
this->origViewWidth = this->getWidth();
|
||||
this->origViewHeight = this->getHeight();
|
||||
}
|
||||
|
||||
nvgImageSize(vg, this->texture, &this->imageWidth, &this->imageHeight);
|
||||
|
||||
this->setWidth(this->origViewWidth);
|
||||
this->setHeight(this->origViewHeight);
|
||||
|
||||
this->imageX = 0;
|
||||
this->imageY = 0;
|
||||
|
||||
float viewAspectRatio = static_cast<float>(this->getWidth()) / static_cast<float>(this->getHeight());
|
||||
float imageAspectRatio = static_cast<float>(this->imageWidth) / static_cast<float>(this->imageHeight);
|
||||
|
||||
switch (imageScaleType)
|
||||
{
|
||||
case ImageScaleType::NO_RESIZE:
|
||||
this->imageX = (this->origViewWidth - this->imageWidth) / 2.0F;
|
||||
this->imageY = (this->origViewHeight - this->imageHeight) / 2.0F;
|
||||
break;
|
||||
case ImageScaleType::FIT:
|
||||
if (viewAspectRatio >= imageAspectRatio)
|
||||
{
|
||||
this->imageHeight = this->getHeight();
|
||||
this->imageWidth = this->imageHeight * imageAspectRatio;
|
||||
this->imageX = (this->origViewWidth - this->imageWidth) / 2.0F;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->imageWidth = this->getWidth();
|
||||
this->imageHeight = this->imageWidth * imageAspectRatio;
|
||||
this->imageY = (this->origViewHeight - this->imageHeight) / 2.0F;
|
||||
}
|
||||
break;
|
||||
case ImageScaleType::CROP:
|
||||
if (viewAspectRatio < imageAspectRatio)
|
||||
{
|
||||
this->imageHeight = this->getHeight();
|
||||
this->imageWidth = this->imageHeight * imageAspectRatio;
|
||||
this->imageX = (this->origViewWidth - this->imageWidth) / 2.0F;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->imageWidth = this->getWidth();
|
||||
this->imageHeight = this->imageWidth * imageAspectRatio;
|
||||
this->imageY = (this->origViewHeight - this->imageHeight) / 2.0F;
|
||||
}
|
||||
break;
|
||||
case ImageScaleType::SCALE:
|
||||
this->imageWidth = this->getWidth();
|
||||
this->imageHeight = this->getHeight();
|
||||
break;
|
||||
case ImageScaleType::VIEW_RESIZE:
|
||||
this->setWidth(this->imageWidth);
|
||||
this->setHeight(this->imageHeight);
|
||||
break;
|
||||
}
|
||||
|
||||
this->imgPaint = nvgImagePattern(vg, getX() + this->imageX, getY() + this->imageY, this->imageWidth, this->imageHeight, 0, this->texture, this->alpha);
|
||||
}
|
||||
|
||||
void Image::setImage(unsigned char* buffer, size_t bufferSize)
|
||||
{
|
||||
if (this->imageBuffer != nullptr)
|
||||
delete[] this->imageBuffer;
|
||||
|
||||
this->imagePath = "";
|
||||
|
||||
this->imageBuffer = new unsigned char[bufferSize];
|
||||
std::memcpy(this->imageBuffer, buffer, bufferSize);
|
||||
this->imageBufferSize = bufferSize;
|
||||
|
||||
this->reloadTexture();
|
||||
this->invalidate();
|
||||
}
|
||||
|
||||
void Image::setImage(std::string imagePath)
|
||||
{
|
||||
this->imagePath = imagePath;
|
||||
|
||||
if (this->imageBuffer != nullptr)
|
||||
delete[] this->imageBuffer;
|
||||
|
||||
this->imageBuffer = nullptr;
|
||||
|
||||
this->reloadTexture();
|
||||
|
||||
this->invalidate();
|
||||
}
|
||||
|
||||
void Image::setOpacity(float opacity)
|
||||
{
|
||||
this->alpha = opacity;
|
||||
this->invalidate();
|
||||
}
|
||||
|
||||
void Image::setScaleType(ImageScaleType imageScaleType)
|
||||
{
|
||||
this->imageScaleType = imageScaleType;
|
||||
this->invalidate();
|
||||
}
|
||||
|
||||
} // namespace brls
|
||||
229
lib/borealis/library/lib/label.cpp
Normal file
229
lib/borealis/library/lib/label.cpp
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019-2020 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <borealis/application.hpp>
|
||||
#include <borealis/label.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
Label::Label(LabelStyle labelStyle, std::string text, bool multiline)
|
||||
: text(text)
|
||||
, multiline(multiline)
|
||||
, labelStyle(labelStyle)
|
||||
{
|
||||
Style* style = Application::getStyle();
|
||||
this->lineHeight = style->Label.lineHeight;
|
||||
|
||||
switch (labelStyle)
|
||||
{
|
||||
case LabelStyle::REGULAR:
|
||||
this->fontSize = style->Label.regularFontSize;
|
||||
break;
|
||||
case LabelStyle::MEDIUM:
|
||||
this->fontSize = style->Label.mediumFontSize;
|
||||
break;
|
||||
case LabelStyle::SMALL:
|
||||
this->fontSize = style->Label.smallFontSize;
|
||||
break;
|
||||
case LabelStyle::DESCRIPTION:
|
||||
this->fontSize = style->Label.descriptionFontSize;
|
||||
break;
|
||||
case LabelStyle::CRASH:
|
||||
this->fontSize = style->Label.crashFontSize;
|
||||
break;
|
||||
case LabelStyle::BUTTON_PLAIN_DISABLED:
|
||||
case LabelStyle::BUTTON_PLAIN:
|
||||
case LabelStyle::BUTTON_BORDERLESS:
|
||||
case LabelStyle::BUTTON_DIALOG:
|
||||
this->fontSize = style->Label.buttonFontSize;
|
||||
break;
|
||||
case LabelStyle::LIST_ITEM:
|
||||
this->fontSize = style->Label.listItemFontSize;
|
||||
break;
|
||||
case LabelStyle::NOTIFICATION:
|
||||
this->fontSize = style->Label.notificationFontSize;
|
||||
this->lineHeight = style->Label.notificationLineHeight;
|
||||
break;
|
||||
case LabelStyle::DIALOG:
|
||||
this->fontSize = style->Label.dialogFontSize;
|
||||
break;
|
||||
case LabelStyle::HINT:
|
||||
this->fontSize = style->Label.hintFontSize;
|
||||
}
|
||||
}
|
||||
|
||||
void Label::setHorizontalAlign(NVGalign align)
|
||||
{
|
||||
this->horizontalAlign = align;
|
||||
}
|
||||
|
||||
void Label::setVerticalAlign(NVGalign align)
|
||||
{
|
||||
this->verticalAlign = align;
|
||||
}
|
||||
|
||||
void Label::setFontSize(unsigned size)
|
||||
{
|
||||
this->fontSize = size;
|
||||
|
||||
if (this->getParent())
|
||||
this->getParent()->invalidate();
|
||||
}
|
||||
|
||||
void Label::setText(std::string text)
|
||||
{
|
||||
this->text = text;
|
||||
|
||||
if (this->hasParent())
|
||||
this->getParent()->invalidate();
|
||||
}
|
||||
|
||||
void Label::setStyle(LabelStyle style)
|
||||
{
|
||||
this->labelStyle = style;
|
||||
}
|
||||
|
||||
void Label::layout(NVGcontext* vg, Style* style, FontStash* stash)
|
||||
{
|
||||
nvgSave(vg);
|
||||
nvgReset(vg);
|
||||
|
||||
nvgFontSize(vg, this->fontSize);
|
||||
nvgTextAlign(vg, this->horizontalAlign | NVG_ALIGN_TOP);
|
||||
nvgFontFaceId(vg, this->getFont(stash));
|
||||
nvgTextLineHeight(vg, this->lineHeight);
|
||||
|
||||
float bounds[4];
|
||||
|
||||
// Update width or height to text bounds
|
||||
if (this->multiline)
|
||||
{
|
||||
nvgTextBoxBounds(vg, this->x, this->y, this->width, this->text.c_str(), nullptr, bounds);
|
||||
|
||||
this->height = bounds[3] - bounds[1]; // ymax - ymin
|
||||
}
|
||||
else
|
||||
{
|
||||
nvgTextBounds(vg, this->x, this->y, this->text.c_str(), nullptr, bounds);
|
||||
|
||||
unsigned oldWidth = this->width;
|
||||
this->width = bounds[2] - bounds[0]; // xmax - xmin
|
||||
|
||||
// offset the position to compensate the width change
|
||||
// and keep right alignment
|
||||
if (this->horizontalAlign == NVG_ALIGN_RIGHT)
|
||||
this->x += oldWidth - this->width;
|
||||
}
|
||||
|
||||
nvgRestore(vg);
|
||||
}
|
||||
|
||||
void Label::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx)
|
||||
{
|
||||
nvgFillColor(vg, this->getColor(ctx->theme));
|
||||
|
||||
// Draw
|
||||
nvgFontSize(vg, this->fontSize);
|
||||
nvgFontFaceId(vg, this->getFont(ctx->fontStash));
|
||||
|
||||
if (this->multiline)
|
||||
{
|
||||
nvgTextLineHeight(vg, this->lineHeight);
|
||||
nvgTextAlign(vg, this->horizontalAlign | NVG_ALIGN_TOP);
|
||||
nvgBeginPath(vg);
|
||||
|
||||
nvgTextBox(vg, x, y, width, this->text.c_str(), nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
nvgTextLineHeight(vg, 1.0f);
|
||||
nvgTextAlign(vg, this->horizontalAlign | this->verticalAlign);
|
||||
nvgBeginPath(vg);
|
||||
|
||||
if (this->horizontalAlign == NVG_ALIGN_RIGHT)
|
||||
x += width;
|
||||
else if (this->horizontalAlign == NVG_ALIGN_CENTER)
|
||||
x += width / 2;
|
||||
|
||||
// TODO: Ticker
|
||||
|
||||
if (this->verticalAlign == NVG_ALIGN_BOTTOM)
|
||||
nvgText(vg, x, y + height, this->text.c_str(), nullptr);
|
||||
else
|
||||
nvgText(vg, x, y + height / 2, this->text.c_str(), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void Label::setColor(NVGcolor color)
|
||||
{
|
||||
this->customColor = color;
|
||||
this->useCustomColor = true;
|
||||
}
|
||||
|
||||
void Label::unsetColor()
|
||||
{
|
||||
this->useCustomColor = false;
|
||||
}
|
||||
|
||||
NVGcolor Label::getColor(ThemeValues* theme)
|
||||
{
|
||||
// Use custom color if any
|
||||
if (this->useCustomColor)
|
||||
return a(this->customColor);
|
||||
|
||||
switch (this->labelStyle)
|
||||
{
|
||||
case LabelStyle::DESCRIPTION:
|
||||
return a(theme->descriptionColor);
|
||||
case LabelStyle::CRASH:
|
||||
return RGB(255, 255, 255);
|
||||
case LabelStyle::BUTTON_PLAIN:
|
||||
return a(theme->buttonPlainEnabledTextColor);
|
||||
case LabelStyle::BUTTON_PLAIN_DISABLED:
|
||||
return a(theme->buttonPlainDisabledTextColor);
|
||||
case LabelStyle::NOTIFICATION:
|
||||
return a(theme->notificationTextColor);
|
||||
case LabelStyle::BUTTON_DIALOG:
|
||||
return a(theme->dialogButtonColor);
|
||||
default:
|
||||
return a(theme->textColor);
|
||||
}
|
||||
}
|
||||
|
||||
void Label::setFont(int font)
|
||||
{
|
||||
this->customFont = font;
|
||||
this->useCustomFont = true;
|
||||
}
|
||||
|
||||
void Label::unsetFont()
|
||||
{
|
||||
this->useCustomFont = false;
|
||||
}
|
||||
|
||||
int Label::getFont(FontStash* stash)
|
||||
{
|
||||
if (this->useCustomFont)
|
||||
return this->customFont;
|
||||
|
||||
return stash->regular;
|
||||
}
|
||||
|
||||
} // namespace brls
|
||||
127
lib/borealis/library/lib/layer_view.cpp
Normal file
127
lib/borealis/library/lib/layer_view.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 WerWolv
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <borealis/application.hpp>
|
||||
#include <borealis/layer_view.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
LayerView::LayerView()
|
||||
{
|
||||
}
|
||||
|
||||
LayerView::~LayerView()
|
||||
{
|
||||
for (unsigned int i = 0; i < this->layers.size(); i++)
|
||||
delete this->layers[i];
|
||||
|
||||
this->layers.clear();
|
||||
}
|
||||
|
||||
void LayerView::addLayer(View* view)
|
||||
{
|
||||
if (view)
|
||||
{
|
||||
view->setParent(this);
|
||||
this->layers.push_back(view);
|
||||
}
|
||||
}
|
||||
|
||||
void LayerView::changeLayer(int index, bool focus)
|
||||
{
|
||||
if (index >= 0 && index < static_cast<int>(this->layers.size()))
|
||||
{
|
||||
Application::blockInputs();
|
||||
|
||||
if (this->selectedIndex >= 0)
|
||||
{
|
||||
this->layers[this->selectedIndex]->willDisappear(true);
|
||||
this->layers[this->selectedIndex]->hide([]() {});
|
||||
}
|
||||
|
||||
this->selectedIndex = index;
|
||||
this->layers[this->selectedIndex]->willAppear(true);
|
||||
this->layers[this->selectedIndex]->show([=]() {
|
||||
if (focus)
|
||||
Application::giveFocus(this->layers[this->selectedIndex]->getDefaultFocus());
|
||||
Application::unblockInputs();
|
||||
});
|
||||
|
||||
this->layers[index]->invalidate();
|
||||
}
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
if (this->selectedIndex > 0)
|
||||
{
|
||||
this->layers[this->selectedIndex]->willDisappear(true);
|
||||
this->layers[this->selectedIndex]->hide([]() {});
|
||||
}
|
||||
|
||||
this->selectedIndex = index;
|
||||
}
|
||||
}
|
||||
|
||||
int LayerView::getLayerIndex()
|
||||
{
|
||||
return this->selectedIndex;
|
||||
}
|
||||
|
||||
View* LayerView::getDefaultFocus()
|
||||
{
|
||||
if (this->selectedIndex >= 0 && this->selectedIndex < static_cast<int>(this->layers.size()))
|
||||
{
|
||||
View* newFocus = this->layers[this->selectedIndex]->getDefaultFocus();
|
||||
if (newFocus)
|
||||
{
|
||||
return newFocus;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void LayerView::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx)
|
||||
{
|
||||
if (this->selectedIndex >= 0 && this->selectedIndex < static_cast<int>(this->layers.size()))
|
||||
this->layers[this->selectedIndex]->frame(ctx);
|
||||
}
|
||||
|
||||
void LayerView::layout(NVGcontext* vg, Style* style, FontStash* stash)
|
||||
{
|
||||
if (this->selectedIndex >= 0 && this->selectedIndex < static_cast<int>(this->layers.size()))
|
||||
{
|
||||
this->layers[this->selectedIndex]->setBoundaries(this->getX(), this->getY(), this->getWidth(), this->getHeight());
|
||||
this->layers[this->selectedIndex]->invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void LayerView::willAppear(bool resetState)
|
||||
{
|
||||
if (this->selectedIndex >= 0 && this->selectedIndex < static_cast<int>(this->layers.size()))
|
||||
this->layers[this->selectedIndex]->willAppear(true);
|
||||
}
|
||||
|
||||
void LayerView::willDisappear(bool resetState)
|
||||
{
|
||||
if (this->selectedIndex >= 0 && this->selectedIndex < static_cast<int>(this->layers.size()))
|
||||
this->layers[this->selectedIndex]->willDisappear(true);
|
||||
}
|
||||
|
||||
}
|
||||
623
lib/borealis/library/lib/list.cpp
Normal file
623
lib/borealis/library/lib/list.cpp
Normal file
@@ -0,0 +1,623 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019-2020 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <borealis/animations.hpp>
|
||||
#include <borealis/application.hpp>
|
||||
#include <borealis/dropdown.hpp>
|
||||
#include <borealis/header.hpp>
|
||||
#include <borealis/list.hpp>
|
||||
#include <borealis/logger.hpp>
|
||||
#include <borealis/swkbd.hpp>
|
||||
#include <borealis/table.hpp>
|
||||
|
||||
// TODO: Scrollbar
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
ListContentView::ListContentView(List* list, size_t defaultFocus)
|
||||
: BoxLayout(BoxLayoutOrientation::VERTICAL, defaultFocus)
|
||||
, list(list)
|
||||
{
|
||||
Style* style = Application::getStyle();
|
||||
this->setMargins(style->List.marginTopBottom, style->List.marginLeftRight, style->List.marginTopBottom, style->List.marginLeftRight);
|
||||
this->setSpacing(style->List.spacing);
|
||||
this->setRememberFocus(true);
|
||||
}
|
||||
|
||||
void ListContentView::customSpacing(View* current, View* next, int* spacing)
|
||||
{
|
||||
// Don't add spacing to the first list item
|
||||
// if it doesn't have a description and the second one is a
|
||||
// list item too
|
||||
// Or if the next item is a ListItemGroupSpacing
|
||||
if (ListItem* currentItem = dynamic_cast<ListItem*>(current))
|
||||
{
|
||||
if (currentItem->getReduceDescriptionSpacing())
|
||||
{
|
||||
if (next != nullptr)
|
||||
*spacing /= 2;
|
||||
}
|
||||
else if (ListItem* nextItem = dynamic_cast<ListItem*>(next))
|
||||
{
|
||||
if (!currentItem->hasDescription())
|
||||
{
|
||||
*spacing = 2;
|
||||
|
||||
nextItem->setDrawTopSeparator(currentItem->isCollapsed());
|
||||
}
|
||||
}
|
||||
else if (dynamic_cast<ListItemGroupSpacing*>(next))
|
||||
{
|
||||
*spacing = 0;
|
||||
}
|
||||
else if (dynamic_cast<Table*>(next))
|
||||
{
|
||||
*spacing /= 2;
|
||||
}
|
||||
}
|
||||
// Table custom spacing
|
||||
else if (dynamic_cast<Table*>(current))
|
||||
{
|
||||
*spacing /= 2;
|
||||
}
|
||||
// ListItemGroupSpacing custom spacing
|
||||
else if (dynamic_cast<ListItemGroupSpacing*>(current))
|
||||
{
|
||||
*spacing /= 2;
|
||||
}
|
||||
// Header custom spacing
|
||||
else if (dynamic_cast<Header*>(current) || dynamic_cast<Header*>(next))
|
||||
{
|
||||
if (dynamic_cast<Header*>(current) && dynamic_cast<ListItem*>(next))
|
||||
{
|
||||
*spacing = 1;
|
||||
}
|
||||
else if (dynamic_cast<Label*>(current) && dynamic_cast<Header*>(next))
|
||||
{
|
||||
// Keep default spacing
|
||||
}
|
||||
else
|
||||
{
|
||||
Style* style = Application::getStyle();
|
||||
*spacing = style->Header.padding;
|
||||
}
|
||||
}
|
||||
|
||||
// Call list custom spacing
|
||||
if (this->list)
|
||||
this->list->customSpacing(current, next, spacing);
|
||||
}
|
||||
|
||||
ListItem::ListItem(std::string label, std::string description, std::string subLabel)
|
||||
: label(label)
|
||||
, subLabel(subLabel)
|
||||
{
|
||||
Style* style = Application::getStyle();
|
||||
|
||||
this->setHeight(subLabel != "" ? style->List.Item.heightWithSubLabel : style->List.Item.height);
|
||||
this->setTextSize(style->Label.listItemFontSize);
|
||||
|
||||
if (description != "")
|
||||
{
|
||||
this->descriptionView = new Label(LabelStyle::DESCRIPTION, description, true);
|
||||
this->descriptionView->setParent(this);
|
||||
}
|
||||
|
||||
this->registerAction("OK", Key::A, [this] { return this->onClick(); });
|
||||
}
|
||||
|
||||
void ListItem::setThumbnail(Image* image)
|
||||
{
|
||||
if (this->thumbnailView)
|
||||
delete this->thumbnailView;
|
||||
if (image != NULL)
|
||||
{
|
||||
this->thumbnailView = image;
|
||||
this->thumbnailView->setParent(this);
|
||||
this->invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void ListItem::setThumbnail(std::string imagePath)
|
||||
{
|
||||
if (this->thumbnailView)
|
||||
this->thumbnailView->setImage(imagePath);
|
||||
else
|
||||
this->thumbnailView = new Image(imagePath);
|
||||
|
||||
this->thumbnailView->setParent(this);
|
||||
this->thumbnailView->setScaleType(ImageScaleType::FIT);
|
||||
this->invalidate();
|
||||
}
|
||||
|
||||
void ListItem::setThumbnail(unsigned char* buffer, size_t bufferSize)
|
||||
{
|
||||
if (this->thumbnailView)
|
||||
this->thumbnailView->setImage(buffer, bufferSize);
|
||||
else
|
||||
this->thumbnailView = new Image(buffer, bufferSize);
|
||||
|
||||
this->thumbnailView->setParent(this);
|
||||
this->thumbnailView->setScaleType(ImageScaleType::FIT);
|
||||
this->invalidate();
|
||||
}
|
||||
|
||||
bool ListItem::getReduceDescriptionSpacing()
|
||||
{
|
||||
return this->reduceDescriptionSpacing;
|
||||
}
|
||||
|
||||
void ListItem::setReduceDescriptionSpacing(bool value)
|
||||
{
|
||||
this->reduceDescriptionSpacing = value;
|
||||
}
|
||||
|
||||
void ListItem::setIndented(bool indented)
|
||||
{
|
||||
this->indented = indented;
|
||||
}
|
||||
|
||||
void ListItem::setTextSize(unsigned textSize)
|
||||
{
|
||||
this->textSize = textSize;
|
||||
}
|
||||
|
||||
void ListItem::setChecked(bool checked)
|
||||
{
|
||||
this->checked = checked;
|
||||
}
|
||||
|
||||
bool ListItem::onClick()
|
||||
{
|
||||
return this->clickEvent.fire(this);
|
||||
}
|
||||
|
||||
GenericEvent* ListItem::getClickEvent()
|
||||
{
|
||||
return &this->clickEvent;
|
||||
}
|
||||
|
||||
void ListItem::layout(NVGcontext* vg, Style* style, FontStash* stash)
|
||||
{
|
||||
// Description
|
||||
if (this->descriptionView)
|
||||
{
|
||||
unsigned indent = style->List.Item.descriptionIndent;
|
||||
|
||||
if (this->indented)
|
||||
indent += style->List.Item.indent;
|
||||
|
||||
this->height = style->List.Item.height;
|
||||
this->descriptionView->setBoundaries(this->x + indent, this->y + this->height + style->List.Item.descriptionSpacing, this->width - indent * 2, 0);
|
||||
this->descriptionView->invalidate(true); // we must call layout directly
|
||||
this->height += this->descriptionView->getHeight() + style->List.Item.descriptionSpacing;
|
||||
}
|
||||
|
||||
// Thumbnail
|
||||
if (this->thumbnailView)
|
||||
{
|
||||
Style* style = Application::getStyle();
|
||||
unsigned thumbnailSize = height - style->List.Item.thumbnailPadding * 2;
|
||||
|
||||
this->thumbnailView->setBoundaries(
|
||||
x + style->List.Item.thumbnailPadding,
|
||||
y + style->List.Item.thumbnailPadding,
|
||||
thumbnailSize,
|
||||
thumbnailSize);
|
||||
this->thumbnailView->invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void ListItem::getHighlightInsets(unsigned* top, unsigned* right, unsigned* bottom, unsigned* left)
|
||||
{
|
||||
Style* style = Application::getStyle();
|
||||
View::getHighlightInsets(top, right, bottom, left);
|
||||
|
||||
if (descriptionView)
|
||||
*bottom = -(descriptionView->getHeight() + style->List.Item.descriptionSpacing);
|
||||
|
||||
if (indented)
|
||||
*left = -style->List.Item.indent;
|
||||
}
|
||||
|
||||
void ListItem::resetValueAnimation()
|
||||
{
|
||||
this->valueAnimation = 0.0f;
|
||||
|
||||
menu_animation_ctx_tag tag = (uintptr_t) & this->valueAnimation;
|
||||
menu_animation_kill_by_tag(&tag);
|
||||
}
|
||||
|
||||
void ListItem::setValue(std::string value, bool faint, bool animate)
|
||||
{
|
||||
this->oldValue = this->value;
|
||||
this->oldValueFaint = this->valueFaint;
|
||||
|
||||
this->value = value;
|
||||
this->valueFaint = faint;
|
||||
|
||||
this->resetValueAnimation();
|
||||
|
||||
if (animate && this->oldValue != "")
|
||||
{
|
||||
Style* style = Application::getStyle();
|
||||
|
||||
menu_animation_ctx_tag tag = (uintptr_t) & this->valueAnimation;
|
||||
menu_animation_ctx_entry_t entry;
|
||||
|
||||
entry.cb = [this](void* userdata) { this->resetValueAnimation(); };
|
||||
entry.duration = style->AnimationDuration.highlight;
|
||||
entry.easing_enum = EASING_IN_OUT_QUAD;
|
||||
entry.subject = &this->valueAnimation;
|
||||
entry.tag = tag;
|
||||
entry.target_value = 1.0f;
|
||||
entry.tick = [](void* userdata) {};
|
||||
entry.userdata = nullptr;
|
||||
|
||||
menu_animation_push(&entry);
|
||||
}
|
||||
}
|
||||
|
||||
std::string ListItem::getValue()
|
||||
{
|
||||
return this->value;
|
||||
}
|
||||
|
||||
void ListItem::setDrawTopSeparator(bool draw)
|
||||
{
|
||||
this->drawTopSeparator = draw;
|
||||
}
|
||||
|
||||
View* ListItem::getDefaultFocus()
|
||||
{
|
||||
if (this->collapseState != 1.0f)
|
||||
return nullptr;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
void ListItem::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx)
|
||||
{
|
||||
unsigned baseHeight = this->height;
|
||||
bool hasSubLabel = this->subLabel != "";
|
||||
bool hasThumbnail = this->thumbnailView;
|
||||
|
||||
unsigned leftPadding = hasThumbnail ? this->thumbnailView->getWidth() + style->List.Item.thumbnailPadding * 2 : style->List.Item.padding;
|
||||
|
||||
if (this->indented)
|
||||
{
|
||||
x += style->List.Item.indent;
|
||||
width -= style->List.Item.indent;
|
||||
}
|
||||
|
||||
// Description
|
||||
if (this->descriptionView)
|
||||
{
|
||||
// Don't count description as part of list item
|
||||
baseHeight -= this->descriptionView->getHeight() + style->List.Item.descriptionSpacing;
|
||||
this->descriptionView->frame(ctx);
|
||||
}
|
||||
|
||||
// Value
|
||||
unsigned valueX = x + width - style->List.Item.padding;
|
||||
unsigned valueY = y + (hasSubLabel ? baseHeight - baseHeight / 3 : baseHeight / 2);
|
||||
|
||||
nvgTextAlign(vg, NVG_ALIGN_RIGHT | (hasSubLabel ? NVG_ALIGN_TOP : NVG_ALIGN_MIDDLE));
|
||||
nvgFontFaceId(vg, ctx->fontStash->regular);
|
||||
if (this->valueAnimation != 0.0f)
|
||||
{
|
||||
//Old value
|
||||
NVGcolor valueColor = a(this->oldValueFaint ? ctx->theme->listItemFaintValueColor : ctx->theme->listItemValueColor);
|
||||
valueColor.a *= (1.0f - this->valueAnimation);
|
||||
nvgFillColor(vg, valueColor);
|
||||
nvgFontSize(vg, style->List.Item.valueSize * (1.0f - this->valueAnimation));
|
||||
nvgBeginPath(vg);
|
||||
nvgText(vg, valueX, valueY, this->oldValue.c_str(), nullptr);
|
||||
|
||||
//New value
|
||||
valueColor = a(this->valueFaint ? ctx->theme->listItemFaintValueColor : ctx->theme->listItemValueColor);
|
||||
valueColor.a *= this->valueAnimation;
|
||||
nvgFillColor(vg, valueColor);
|
||||
nvgFontSize(vg, style->List.Item.valueSize * this->valueAnimation);
|
||||
nvgBeginPath(vg);
|
||||
nvgText(vg, valueX, valueY, this->value.c_str(), nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
nvgFillColor(vg, a(this->valueFaint ? ctx->theme->listItemFaintValueColor : ctx->theme->listItemValueColor));
|
||||
nvgFontSize(vg, style->List.Item.valueSize);
|
||||
nvgFontFaceId(vg, ctx->fontStash->regular);
|
||||
nvgBeginPath(vg);
|
||||
nvgText(vg, valueX, valueY, this->value.c_str(), nullptr);
|
||||
}
|
||||
|
||||
// Checked marker
|
||||
if (this->checked)
|
||||
{
|
||||
unsigned radius = style->List.Item.selectRadius;
|
||||
unsigned centerX = x + width - radius - style->List.Item.padding;
|
||||
unsigned centerY = y + baseHeight / 2;
|
||||
|
||||
float radiusf = (float)radius;
|
||||
|
||||
int thickness = roundf(radiusf * 0.10f);
|
||||
|
||||
// Background
|
||||
nvgFillColor(vg, a(ctx->theme->listItemValueColor));
|
||||
nvgBeginPath(vg);
|
||||
nvgCircle(vg, centerX, centerY, radiusf);
|
||||
nvgFill(vg);
|
||||
|
||||
// Check mark
|
||||
nvgFillColor(vg, a(ctx->theme->backgroundColorRGB));
|
||||
|
||||
// Long stroke
|
||||
nvgSave(vg);
|
||||
nvgTranslate(vg, centerX, centerY);
|
||||
nvgRotate(vg, -NVG_PI / 4.0f);
|
||||
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, -(radiusf * 0.55f), 0, radiusf * 1.3f, thickness);
|
||||
nvgFill(vg);
|
||||
nvgRestore(vg);
|
||||
|
||||
// Short stroke
|
||||
nvgSave(vg);
|
||||
nvgTranslate(vg, centerX - (radiusf * 0.65f), centerY);
|
||||
nvgRotate(vg, NVG_PI / 4.0f);
|
||||
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, 0, -(thickness / 2), radiusf * 0.53f, thickness);
|
||||
nvgFill(vg);
|
||||
|
||||
nvgRestore(vg);
|
||||
}
|
||||
|
||||
// Label
|
||||
nvgFillColor(vg, a(ctx->theme->textColor));
|
||||
nvgFontSize(vg, this->textSize);
|
||||
nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
|
||||
nvgFontFaceId(vg, ctx->fontStash->regular);
|
||||
nvgBeginPath(vg);
|
||||
nvgText(vg, x + leftPadding, y + baseHeight / (hasSubLabel ? 3 : 2), this->label.c_str(), nullptr);
|
||||
|
||||
// Sub Label
|
||||
if (hasSubLabel)
|
||||
{
|
||||
nvgFillColor(vg, a(ctx->theme->descriptionColor));
|
||||
nvgFontSize(vg, style->Label.descriptionFontSize);
|
||||
nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_TOP);
|
||||
nvgFontFaceId(vg, ctx->fontStash->regular);
|
||||
nvgBeginPath(vg);
|
||||
nvgText(vg, x + leftPadding, y + baseHeight - baseHeight / 3, this->subLabel.c_str(), nullptr);
|
||||
}
|
||||
|
||||
// Thumbnail
|
||||
if (hasThumbnail)
|
||||
this->thumbnailView->frame(ctx);
|
||||
|
||||
// Separators
|
||||
// Offset by one to be hidden by highlight
|
||||
nvgFillColor(vg, a(ctx->theme->listItemSeparatorColor));
|
||||
|
||||
// Top
|
||||
if (this->drawTopSeparator)
|
||||
{
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, x, y - 1, width, 1);
|
||||
nvgFill(vg);
|
||||
}
|
||||
|
||||
// Bottom
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, x, y + 1 + baseHeight, width, 1);
|
||||
nvgFill(vg);
|
||||
}
|
||||
|
||||
bool ListItem::hasDescription()
|
||||
{
|
||||
return this->descriptionView;
|
||||
}
|
||||
|
||||
std::string ListItem::getLabel()
|
||||
{
|
||||
return this->label;
|
||||
}
|
||||
|
||||
ListItem::~ListItem()
|
||||
{
|
||||
if (this->descriptionView)
|
||||
delete this->descriptionView;
|
||||
|
||||
if (this->thumbnailView)
|
||||
delete this->thumbnailView;
|
||||
|
||||
this->resetValueAnimation();
|
||||
}
|
||||
|
||||
ToggleListItem::ToggleListItem(std::string label, bool initialValue, std::string description, std::string onValue, std::string offValue)
|
||||
: ListItem(label, description)
|
||||
, toggleState(initialValue)
|
||||
, onValue(onValue)
|
||||
, offValue(offValue)
|
||||
{
|
||||
this->updateValue();
|
||||
}
|
||||
|
||||
void ToggleListItem::updateValue()
|
||||
{
|
||||
if (this->toggleState)
|
||||
this->setValue(this->onValue, false);
|
||||
else
|
||||
this->setValue(this->offValue, true);
|
||||
}
|
||||
|
||||
bool ToggleListItem::onClick()
|
||||
{
|
||||
this->toggleState = !this->toggleState;
|
||||
this->updateValue();
|
||||
|
||||
ListItem::onClick();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ToggleListItem::getToggleState()
|
||||
{
|
||||
return this->toggleState;
|
||||
}
|
||||
|
||||
InputListItem::InputListItem(std::string label, std::string initialValue, std::string helpText, std::string description, int maxInputLength)
|
||||
: ListItem(label, description)
|
||||
, helpText(helpText)
|
||||
, maxInputLength(maxInputLength)
|
||||
{
|
||||
this->setValue(initialValue, false);
|
||||
}
|
||||
|
||||
bool InputListItem::onClick()
|
||||
{
|
||||
Swkbd::openForText([&](std::string text) {
|
||||
this->setValue(text, false);
|
||||
},
|
||||
this->helpText, "", this->maxInputLength, this->getValue());
|
||||
|
||||
ListItem::onClick();
|
||||
return true;
|
||||
}
|
||||
|
||||
IntegerInputListItem::IntegerInputListItem(std::string label, int initialValue, std::string helpText, std::string description, int maxInputLength)
|
||||
: InputListItem(label, std::to_string(initialValue), helpText, description, maxInputLength)
|
||||
{
|
||||
}
|
||||
|
||||
bool IntegerInputListItem::onClick()
|
||||
{
|
||||
Swkbd::openForNumber([&](int number) {
|
||||
this->setValue(std::to_string(number), false);
|
||||
},
|
||||
this->helpText, "", this->maxInputLength, this->getValue());
|
||||
|
||||
ListItem::onClick();
|
||||
return true;
|
||||
}
|
||||
|
||||
ListItemGroupSpacing::ListItemGroupSpacing(bool separator)
|
||||
: Rectangle(nvgRGBA(0, 0, 0, 0))
|
||||
{
|
||||
ThemeValues* theme = Application::getThemeValues();
|
||||
|
||||
if (separator)
|
||||
this->setColor(theme->listItemSeparatorColor);
|
||||
}
|
||||
|
||||
SelectListItem::SelectListItem(std::string label, std::vector<std::string> values, unsigned selectedValue)
|
||||
: ListItem(label, "")
|
||||
, values(values)
|
||||
, selectedValue(selectedValue)
|
||||
{
|
||||
this->setValue(values[selectedValue], false, false);
|
||||
|
||||
this->getClickEvent()->subscribe([this](View* view) {
|
||||
ValueSelectedEvent::Callback valueCallback = [this](int result) {
|
||||
if (result == -1)
|
||||
return;
|
||||
|
||||
this->setValue(this->values[result], false, false);
|
||||
this->selectedValue = result;
|
||||
|
||||
this->valueEvent.fire(result);
|
||||
};
|
||||
Dropdown::open(this->getLabel(), this->values, valueCallback, this->selectedValue);
|
||||
});
|
||||
}
|
||||
|
||||
void SelectListItem::setSelectedValue(unsigned value)
|
||||
{
|
||||
if (value >= 0 && value < this->values.size())
|
||||
{
|
||||
this->selectedValue = value;
|
||||
this->setValue(this->values[value], false, false);
|
||||
}
|
||||
}
|
||||
|
||||
ValueSelectedEvent* SelectListItem::getValueSelectedEvent()
|
||||
{
|
||||
return &this->valueEvent;
|
||||
}
|
||||
|
||||
List::List(size_t defaultFocus)
|
||||
{
|
||||
this->layout = new ListContentView(this, defaultFocus);
|
||||
|
||||
this->layout->setResize(true);
|
||||
this->layout->setParent(this);
|
||||
|
||||
this->setContentView(this->layout);
|
||||
}
|
||||
|
||||
// Wrapped BoxLayout methods
|
||||
|
||||
void List::addView(View* view, bool fill)
|
||||
{
|
||||
this->layout->addView(view, fill);
|
||||
}
|
||||
|
||||
void List::clear(bool free)
|
||||
{
|
||||
this->layout->clear(free);
|
||||
}
|
||||
|
||||
void List::setMargins(unsigned top, unsigned right, unsigned bottom, unsigned left)
|
||||
{
|
||||
this->layout->setMargins(
|
||||
top,
|
||||
right,
|
||||
bottom,
|
||||
left);
|
||||
}
|
||||
|
||||
void List::setSpacing(unsigned spacing)
|
||||
{
|
||||
this->layout->setSpacing(spacing);
|
||||
}
|
||||
|
||||
unsigned List::getSpacing()
|
||||
{
|
||||
return this->layout->getSpacing();
|
||||
}
|
||||
|
||||
void List::setMarginBottom(unsigned bottom)
|
||||
{
|
||||
this->layout->setMarginBottom(bottom);
|
||||
}
|
||||
|
||||
void List::customSpacing(View* current, View* next, int* spacing)
|
||||
{
|
||||
// Nothing to do by default
|
||||
}
|
||||
|
||||
List::~List()
|
||||
{
|
||||
// ScrollView already deletes the content view
|
||||
}
|
||||
|
||||
} // namespace brls
|
||||
73
lib/borealis/library/lib/logger.cpp
Normal file
73
lib/borealis/library/lib/logger.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <borealis/logger.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
static LogLevel g_logLevel = LogLevel::INFO;
|
||||
|
||||
void Logger::setLogLevel(LogLevel newLogLevel)
|
||||
{
|
||||
g_logLevel = newLogLevel;
|
||||
}
|
||||
|
||||
void Logger::log(LogLevel logLevel, const char* prefix, const char* color, const char* format, va_list ap)
|
||||
{
|
||||
if (g_logLevel < logLevel)
|
||||
return;
|
||||
|
||||
printf("\033%s[%s]\033[0m ", color, prefix);
|
||||
vprintf(format, ap);
|
||||
printf("\n");
|
||||
|
||||
#ifdef __MINGW32__
|
||||
fflush(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Logger::error(const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
Logger::log(LogLevel::ERROR, "ERROR", "[0;31m", format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void Logger::info(const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
Logger::log(LogLevel::INFO, "INFO", "[0;34m", format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void Logger::debug(const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
Logger::log(LogLevel::DEBUG, "DEBUG", "[0;32m", format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
} // namespace brls
|
||||
48
lib/borealis/library/lib/material_icon.cpp
Normal file
48
lib/borealis/library/lib/material_icon.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <borealis/material_icon.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
MaterialIcon::MaterialIcon(std::string icon)
|
||||
: icon(icon)
|
||||
{
|
||||
}
|
||||
|
||||
void MaterialIcon::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx)
|
||||
{
|
||||
NVGcolor color = a(ctx->theme->textColor);
|
||||
|
||||
nvgTextLineHeight(vg, 1.0f);
|
||||
nvgFillColor(vg, color);
|
||||
nvgFontSize(vg, height);
|
||||
nvgFontFaceId(vg, ctx->fontStash->material);
|
||||
nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
|
||||
nvgBeginPath(vg);
|
||||
nvgText(vg, this->middleX, this->middleY, this->icon.c_str(), nullptr);
|
||||
}
|
||||
|
||||
void MaterialIcon::layout(NVGcontext* vg, Style* style, FontStash* stash)
|
||||
{
|
||||
this->middleX = this->getX() + this->getWidth() / 2;
|
||||
this->middleY = this->getY() + this->getHeight() / 2;
|
||||
}
|
||||
|
||||
}; // namespace brls
|
||||
205
lib/borealis/library/lib/notification_manager.cpp
Normal file
205
lib/borealis/library/lib/notification_manager.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <borealis/application.hpp>
|
||||
#include <borealis/logger.hpp>
|
||||
#include <borealis/notification_manager.hpp>
|
||||
#include <cstring>
|
||||
|
||||
// TODO: add a timeout duration enum for longer notifications
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
NotificationManager::NotificationManager()
|
||||
{
|
||||
std::memset(this->notifications, 0, sizeof(Notification*) * BRLS_NOTIFICATIONS_MAX);
|
||||
}
|
||||
|
||||
void NotificationManager::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx)
|
||||
{
|
||||
for (size_t i = 0; i < BRLS_NOTIFICATIONS_MAX; i++)
|
||||
{
|
||||
if (this->notifications[i])
|
||||
{
|
||||
Notification* notification = this->notifications[i];
|
||||
|
||||
float alpha = notification->getAlpha();
|
||||
float translation = 0.0f;
|
||||
|
||||
if (alpha != 1.0f)
|
||||
{
|
||||
translation = (1.0f - alpha) * (float)style->Notification.slideAnimation;
|
||||
nvgTranslate(vg, translation, 0);
|
||||
}
|
||||
|
||||
this->notifications[i]->frame(ctx);
|
||||
|
||||
if (alpha != 1.0f)
|
||||
nvgTranslate(vg, -translation, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationManager::notify(std::string text)
|
||||
{
|
||||
// Find the first available notification slot
|
||||
bool found = false;
|
||||
size_t i = 0;
|
||||
for (i = 0; i < BRLS_NOTIFICATIONS_MAX; i++)
|
||||
{
|
||||
if (!this->notifications[i])
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
brls::Logger::info("Discarding notification \"%s\"", text.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the notification
|
||||
brls::Logger::info("Showing notification \"%s\"", text.c_str());
|
||||
|
||||
Notification* notification = new Notification(text);
|
||||
notification->setParent(this);
|
||||
notification->show([]() {});
|
||||
|
||||
// Timeout timer
|
||||
menu_timer_ctx_entry_t entry;
|
||||
|
||||
entry.duration = Application::getStyle()->AnimationDuration.notificationTimeout;
|
||||
entry.tick = [](void*) {};
|
||||
entry.userdata = nullptr;
|
||||
entry.cb = [this, notification, i](void* userdata) {
|
||||
notification->hide([this, notification, i]() {
|
||||
delete notification;
|
||||
this->notifications[i] = nullptr;
|
||||
});
|
||||
};
|
||||
|
||||
menu_timer_start(¬ification->timeoutTimer, &entry);
|
||||
|
||||
this->notifications[i] = notification;
|
||||
|
||||
// Layout the notification
|
||||
this->layoutNotification(i);
|
||||
}
|
||||
|
||||
void NotificationManager::layoutNotification(size_t index)
|
||||
{
|
||||
Notification* notification = this->notifications[index];
|
||||
|
||||
if (!notification)
|
||||
return;
|
||||
|
||||
Style* style = Application::getStyle();
|
||||
|
||||
// Get the position of the last notification
|
||||
Notification* lastNotification = nullptr;
|
||||
for (size_t i = 0; i < index; i++)
|
||||
{
|
||||
if (this->notifications[i])
|
||||
lastNotification = this->notifications[i];
|
||||
}
|
||||
|
||||
unsigned y = lastNotification ? (lastNotification->getY() + lastNotification->getHeight()) : 0;
|
||||
|
||||
// Layout the notification
|
||||
unsigned width = style->Notification.width;
|
||||
notification->setBoundaries(
|
||||
this->getX() + this->getWidth() - width,
|
||||
this->getY() + y,
|
||||
width,
|
||||
0 // height is dynamic
|
||||
);
|
||||
|
||||
notification->invalidate(); // TODO: call layout directly to fix posting multiple notifications in one frame
|
||||
}
|
||||
|
||||
void NotificationManager::layout(NVGcontext* vg, Style* style, FontStash* stash)
|
||||
{
|
||||
for (size_t i = 0; i < BRLS_NOTIFICATIONS_MAX; i++)
|
||||
{
|
||||
if (this->notifications[i])
|
||||
this->layoutNotification(i);
|
||||
}
|
||||
}
|
||||
|
||||
NotificationManager::~NotificationManager()
|
||||
{
|
||||
for (size_t i = 0; i < BRLS_NOTIFICATIONS_MAX; i++)
|
||||
{
|
||||
if (this->notifications[i])
|
||||
delete this->notifications[i];
|
||||
}
|
||||
}
|
||||
|
||||
Notification::Notification(std::string text)
|
||||
{
|
||||
this->setBackground(Background::BACKDROP);
|
||||
|
||||
this->label = new Label(LabelStyle::NOTIFICATION, text, true);
|
||||
label->setParent(this);
|
||||
}
|
||||
|
||||
Notification::~Notification()
|
||||
{
|
||||
delete this->label;
|
||||
}
|
||||
|
||||
void Notification::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx)
|
||||
{
|
||||
this->label->frame(ctx);
|
||||
}
|
||||
|
||||
void Notification::layout(NVGcontext* vg, Style* style, FontStash* stash)
|
||||
{
|
||||
unsigned padding = style->Notification.padding;
|
||||
unsigned fontSize = style->Label.notificationFontSize;
|
||||
float lineHeight = style->Label.notificationLineHeight;
|
||||
|
||||
// Layout the label
|
||||
this->label->setWidth(this->getWidth() - padding * 2);
|
||||
this->label->setHeight(0); // height is dynamic
|
||||
|
||||
this->label->invalidate(true); // layout directly to update height
|
||||
|
||||
unsigned minLabelHeight = (unsigned int)(lineHeight * fontSize) + fontSize; // 2 lines
|
||||
unsigned labelYAdvance = padding;
|
||||
if (this->label->getHeight() < minLabelHeight)
|
||||
{
|
||||
labelYAdvance += (minLabelHeight - this->label->getHeight()) / 2;
|
||||
}
|
||||
|
||||
this->label->setBoundaries(
|
||||
this->getX() + padding,
|
||||
this->getY() + labelYAdvance,
|
||||
this->label->getWidth(),
|
||||
this->label->getHeight());
|
||||
|
||||
// Update our own height
|
||||
this->setHeight(std::max(
|
||||
this->label->getHeight() + padding * 2,
|
||||
minLabelHeight + padding * 2));
|
||||
}
|
||||
|
||||
}; // namespace brls
|
||||
163
lib/borealis/library/lib/popup_frame.cpp
Normal file
163
lib/borealis/library/lib/popup_frame.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 natinusala
|
||||
Copyright (C) 2019 WerWolv
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <borealis/animations.hpp>
|
||||
#include <borealis/application.hpp>
|
||||
#include <borealis/logger.hpp>
|
||||
#include <borealis/popup_frame.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
PopupFrame::PopupFrame(std::string title, unsigned char* imageBuffer, size_t imageBufferSize, AppletFrame* contentView, std::string subTitleLeft, std::string subTitleRight)
|
||||
: contentView(contentView)
|
||||
{
|
||||
if (this->contentView)
|
||||
{
|
||||
this->contentView->setParent(this);
|
||||
this->contentView->setHeaderStyle(HeaderStyle::POPUP);
|
||||
this->contentView->setTitle(title);
|
||||
this->contentView->setSubtitle(subTitleLeft, subTitleRight);
|
||||
this->contentView->setIcon(imageBuffer, imageBufferSize);
|
||||
this->contentView->invalidate();
|
||||
}
|
||||
|
||||
contentView->setAnimateHint(true);
|
||||
this->registerAction("Back", Key::B, [this] { return this->onCancel(); });
|
||||
}
|
||||
|
||||
PopupFrame::PopupFrame(std::string title, std::string imagePath, AppletFrame* contentView, std::string subTitleLeft, std::string subTitleRight)
|
||||
: contentView(contentView)
|
||||
{
|
||||
if (this->contentView)
|
||||
{
|
||||
this->contentView->setParent(this);
|
||||
this->contentView->setHeaderStyle(HeaderStyle::POPUP);
|
||||
this->contentView->setTitle(title);
|
||||
this->contentView->setSubtitle(subTitleLeft, subTitleRight);
|
||||
this->contentView->setIcon(imagePath);
|
||||
this->contentView->invalidate();
|
||||
}
|
||||
|
||||
contentView->setAnimateHint(true);
|
||||
this->registerAction("Back", Key::B, [this] { return this->onCancel(); });
|
||||
}
|
||||
|
||||
PopupFrame::PopupFrame(std::string title, AppletFrame* contentView, std::string subTitleLeft, std::string subTitleRight)
|
||||
: contentView(contentView)
|
||||
{
|
||||
if (this->contentView)
|
||||
{
|
||||
this->contentView->setParent(this);
|
||||
this->contentView->setHeaderStyle(HeaderStyle::POPUP);
|
||||
this->contentView->setTitle(title);
|
||||
this->contentView->setSubtitle(subTitleLeft, subTitleRight);
|
||||
this->contentView->invalidate();
|
||||
}
|
||||
|
||||
contentView->setAnimateHint(true);
|
||||
this->registerAction("Back", Key::B, [this] { return this->onCancel(); });
|
||||
}
|
||||
|
||||
void PopupFrame::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx)
|
||||
{
|
||||
// Backdrop
|
||||
nvgFillColor(vg, a(ctx->theme->dropdownBackgroundColor));
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, 0, y, width, height);
|
||||
nvgFill(vg);
|
||||
|
||||
// Background
|
||||
nvgFillColor(vg, a(ctx->theme->backgroundColorRGB));
|
||||
nvgBeginPath(vg);
|
||||
nvgRect(vg, style->PopupFrame.edgePadding, y, width - style->PopupFrame.edgePadding * 2, height);
|
||||
nvgFill(vg);
|
||||
|
||||
// TODO: Shadow
|
||||
|
||||
// Content view
|
||||
nvgSave(vg);
|
||||
nvgScissor(vg, style->PopupFrame.edgePadding, 0, style->PopupFrame.contentWidth, height);
|
||||
|
||||
this->contentView->frame(ctx);
|
||||
|
||||
nvgRestore(vg);
|
||||
}
|
||||
|
||||
bool PopupFrame::onCancel()
|
||||
{
|
||||
Application::popView();
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned PopupFrame::getShowAnimationDuration(ViewAnimation animation)
|
||||
{
|
||||
return View::getShowAnimationDuration(animation) / 2;
|
||||
}
|
||||
|
||||
void PopupFrame::layout(NVGcontext* vg, Style* style, FontStash* stash)
|
||||
{
|
||||
this->contentView->setBoundaries(style->PopupFrame.edgePadding, 0, style->PopupFrame.contentWidth, this->getHeight());
|
||||
this->contentView->invalidate();
|
||||
}
|
||||
|
||||
View* PopupFrame::getDefaultFocus()
|
||||
{
|
||||
if (this->contentView)
|
||||
return this->contentView->getDefaultFocus();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PopupFrame::open(std::string title, unsigned char* imageBuffer, size_t imageBufferSize, AppletFrame* contentView, std::string subTitleLeft, std::string subTitleRight)
|
||||
{
|
||||
PopupFrame* popupFrame = new PopupFrame(title, imageBuffer, imageBufferSize, contentView, subTitleLeft, subTitleRight);
|
||||
Application::pushView(popupFrame);
|
||||
}
|
||||
|
||||
void PopupFrame::open(std::string title, std::string imagePath, AppletFrame* contentView, std::string subTitleLeft, std::string subTitleRight)
|
||||
{
|
||||
PopupFrame* popupFrame = new PopupFrame(title, imagePath, contentView, subTitleLeft, subTitleRight);
|
||||
Application::pushView(popupFrame);
|
||||
}
|
||||
|
||||
void PopupFrame::open(std::string title, AppletFrame* contentView, std::string subTitleLeft, std::string subTitleRight)
|
||||
{
|
||||
PopupFrame* popupFrame = new PopupFrame(title, contentView, subTitleLeft, subTitleRight);
|
||||
Application::pushView(popupFrame);
|
||||
}
|
||||
|
||||
void PopupFrame::willAppear(bool resetState)
|
||||
{
|
||||
this->contentView->willAppear(resetState);
|
||||
}
|
||||
|
||||
void PopupFrame::willDisappear(bool resetState)
|
||||
{
|
||||
this->contentView->willDisappear(resetState);
|
||||
}
|
||||
|
||||
PopupFrame::~PopupFrame()
|
||||
{
|
||||
if (this->contentView)
|
||||
delete this->contentView;
|
||||
}
|
||||
|
||||
} // namespace brls
|
||||
134
lib/borealis/library/lib/progress_display.cpp
Normal file
134
lib/borealis/library/lib/progress_display.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
Borealis, a Nintendo Switch UI Library
|
||||
Copyright (C) 2019 Billy Laws
|
||||
Copyright (C) 2019 p-sam
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <borealis/application.hpp>
|
||||
#include <borealis/progress_display.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
ProgressDisplay::ProgressDisplay(ProgressDisplayFlags progressFlags)
|
||||
{
|
||||
if (progressFlags & ProgressDisplayFlags::PERCENTAGE)
|
||||
this->label = new Label(LabelStyle::DIALOG, "0%", false);
|
||||
if (progressFlags & ProgressDisplayFlags::SPINNER)
|
||||
this->spinner = new ProgressSpinner();
|
||||
}
|
||||
|
||||
void ProgressDisplay::setProgress(int current, int max)
|
||||
{
|
||||
if (current > max)
|
||||
return;
|
||||
|
||||
this->progressPercentage = ((current * 100) / max);
|
||||
|
||||
if (!this->label)
|
||||
return;
|
||||
|
||||
std::string labelText = std::to_string((unsigned)this->progressPercentage);
|
||||
labelText += "%";
|
||||
this->label->setText(labelText);
|
||||
}
|
||||
|
||||
void ProgressDisplay::layout(NVGcontext* vg, Style* style, FontStash* stash)
|
||||
{
|
||||
if (this->label)
|
||||
{
|
||||
this->label->setWidth(style->ProgressDisplay.percentageLabelWidth);
|
||||
this->label->invalidate(true);
|
||||
this->label->setBoundaries(
|
||||
this->x + this->width - this->label->getWidth() / 2,
|
||||
this->y + this->height / 2 - this->label->getHeight() / 2,
|
||||
this->label->getWidth(),
|
||||
this->label->getHeight());
|
||||
}
|
||||
|
||||
if (this->spinner)
|
||||
{
|
||||
this->spinner->setWidth(this->height);
|
||||
this->spinner->setHeight(this->height);
|
||||
this->spinner->setBoundaries(
|
||||
this->x,
|
||||
this->y,
|
||||
this->spinner->getWidth(),
|
||||
this->spinner->getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
void ProgressDisplay::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx)
|
||||
{
|
||||
unsigned progressBarWidth = width;
|
||||
unsigned progressBarX = x;
|
||||
|
||||
if (this->label)
|
||||
{
|
||||
progressBarWidth -= this->label->getWidth();
|
||||
this->label->frame(ctx);
|
||||
}
|
||||
|
||||
if (this->spinner)
|
||||
{
|
||||
// 1.25 accounts for the extra width of the curve on sides of progress bar
|
||||
progressBarWidth -= this->spinner->getWidth() * 1.25f;
|
||||
progressBarX += this->spinner->getWidth() * 1.25f;
|
||||
this->spinner->frame(ctx);
|
||||
}
|
||||
|
||||
nvgBeginPath(vg);
|
||||
nvgMoveTo(vg, progressBarX, y + height / 2);
|
||||
nvgLineTo(vg, progressBarX + progressBarWidth, y + height / 2);
|
||||
nvgStrokeColor(vg, a(ctx->theme->listItemSeparatorColor));
|
||||
nvgStrokeWidth(vg, height / 3);
|
||||
nvgLineCap(vg, NVG_ROUND);
|
||||
nvgStroke(vg);
|
||||
|
||||
if (this->progressPercentage > 0.0f)
|
||||
{
|
||||
nvgBeginPath(vg);
|
||||
nvgMoveTo(vg, progressBarX, y + height / 2);
|
||||
nvgLineTo(vg, progressBarX + ((float)progressBarWidth * this->progressPercentage) / 100, y + height / 2);
|
||||
nvgStrokeColor(vg, a(ctx->theme->listItemValueColor));
|
||||
nvgStrokeWidth(vg, height / 3);
|
||||
nvgLineCap(vg, NVG_ROUND);
|
||||
nvgStroke(vg);
|
||||
}
|
||||
}
|
||||
|
||||
void ProgressDisplay::willAppear(bool resetState)
|
||||
{
|
||||
if (this->spinner)
|
||||
this->spinner->willAppear(resetState);
|
||||
}
|
||||
|
||||
void ProgressDisplay::willDisappear(bool resetState)
|
||||
{
|
||||
if (this->spinner)
|
||||
this->spinner->willDisappear(resetState);
|
||||
}
|
||||
|
||||
ProgressDisplay::~ProgressDisplay()
|
||||
{
|
||||
if (this->spinner)
|
||||
delete this->spinner;
|
||||
|
||||
if (this->label)
|
||||
delete this->label;
|
||||
}
|
||||
|
||||
} // namespace brls
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user