initial commit version 0.0.1
340
COPYING
Normal file
@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) 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
|
||||
this service 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 make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. 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.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
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
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the 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 a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE 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.
|
||||
|
||||
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
|
||||
convey 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 2 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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision 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, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This 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.
|
7
HISTORY
Normal file
@ -0,0 +1,7 @@
|
||||
VDR Plugin 'skindesigner' Revision History
|
||||
---------------------------------------
|
||||
|
||||
2014-09-27: Version 0.0.1
|
||||
|
||||
- Initial revision.
|
||||
|
176
Makefile
Normal file
@ -0,0 +1,176 @@
|
||||
#
|
||||
# Makefile for a Video Disk Recorder plugin
|
||||
#
|
||||
# $Id$ Makefile 1.0 2014/07/24 louis Exp $
|
||||
|
||||
# External image lib to use: imagemagick, graphicsmagick
|
||||
IMAGELIB = imagemagick
|
||||
|
||||
# The official name of this plugin.
|
||||
PLUGIN = skindesigner
|
||||
|
||||
### The version number of this plugin (taken from the main source file):
|
||||
VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g')
|
||||
|
||||
### The directory environment:
|
||||
|
||||
# Use package data if installed...otherwise assume we're under the VDR source directory:
|
||||
PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell pkg-config --variable=$(1) vdr || pkg-config --variable=$(1) ../../../vdr.pc))
|
||||
LIBDIR = $(call PKGCFG,libdir)
|
||||
LOCDIR = $(call PKGCFG,locdir)
|
||||
PLGCFG = $(call PKGCFG,plgcfg)
|
||||
VDRCONFDIR = $(call PKGCFG,configdir)
|
||||
PLGRESDIR = $(call PKGCFG,resdir)/plugins/$(PLUGIN)
|
||||
TMPDIR ?= /tmp
|
||||
|
||||
### The compiler options:
|
||||
export CFLAGS = $(call PKGCFG,cflags)
|
||||
export CXXFLAGS = $(call PKGCFG,cxxflags)
|
||||
|
||||
### Allow user defined options to overwrite defaults:
|
||||
|
||||
-include $(PLGCFG)
|
||||
|
||||
### The version number of VDR's plugin API:
|
||||
APIVERSION = $(call PKGCFG,apiversion)
|
||||
|
||||
### The name of the distribution archive:
|
||||
ARCHIVE = $(PLUGIN)-$(VERSION)
|
||||
PACKAGE = vdr-$(ARCHIVE)
|
||||
|
||||
### The name of the shared object file:
|
||||
SOFILE = libvdr-$(PLUGIN).so
|
||||
|
||||
### Includes and Defines and Dependencies:
|
||||
DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
|
||||
DEFINES += $(shell xml2-config --cflags)
|
||||
|
||||
INCLUDES += $(shell pkg-config --cflags freetype2 fontconfig)
|
||||
|
||||
ifeq ($(IMAGELIB), imagemagick)
|
||||
INCLUDES += $(shell pkg-config --cflags Magick++)
|
||||
LIBS += $(shell pkg-config --libs Magick++)
|
||||
else ifeq ($(IMAGELIB), graphicsmagick)
|
||||
INCLUDES += $(shell pkg-config --cflags GraphicsMagick++)
|
||||
LIBS += $(shell pkg-config --libs GraphicsMagick++)
|
||||
endif
|
||||
|
||||
LIBS += $(shell xml2-config --libs)
|
||||
|
||||
### The object files:
|
||||
OBJS = $(PLUGIN).o \
|
||||
config.o \
|
||||
setup.o \
|
||||
designer.o \
|
||||
displaychannel.o \
|
||||
displaymenu.o \
|
||||
displaymessage.o \
|
||||
displayreplay.o \
|
||||
displaytracks.o \
|
||||
displayvolume.o \
|
||||
libcore/pixmapcontainer.o \
|
||||
libcore/fontmanager.o \
|
||||
libcore/imagecache.o \
|
||||
libcore/imagemagickwrapper.o \
|
||||
libcore/imagescaler.o \
|
||||
libcore/helpers.o \
|
||||
libcore/imageloader.o \
|
||||
libcore/timers.o \
|
||||
libtemplate/globals.o \
|
||||
libtemplate/parameter.o \
|
||||
libtemplate/template.o \
|
||||
libtemplate/templateview.o \
|
||||
libtemplate/templateviewelement.o \
|
||||
libtemplate/templateviewlist.o \
|
||||
libtemplate/templatepixmap.o \
|
||||
libtemplate/templateviewtab.o \
|
||||
libtemplate/templatefunction.o \
|
||||
libtemplate/templateloopfunction.o \
|
||||
libtemplate/xmlparser.o \
|
||||
views/view.o \
|
||||
views/displaychannelview.o \
|
||||
views/displaymenurootview.o \
|
||||
views/displaymenuview.o \
|
||||
views/displaymenulistview.o \
|
||||
views/displaymenuitemview.o \
|
||||
views/displaymenuitemcurrentview.o \
|
||||
views/displaymenudetailview.o \
|
||||
views/displaymenutabview.o \
|
||||
views/displaymessageview.o \
|
||||
views/displayreplayview.o \
|
||||
views/displayvolumeview.o \
|
||||
views/displayaudiotracksview.o
|
||||
|
||||
### The main target:
|
||||
|
||||
all: $(SOFILE) i18n
|
||||
|
||||
### Implicit rules:
|
||||
|
||||
%.o: %.c
|
||||
$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
|
||||
|
||||
### Dependencies:
|
||||
|
||||
MAKEDEP = $(CXX) -MM -MG
|
||||
DEPFILE = .dependencies
|
||||
$(DEPFILE): Makefile
|
||||
@$(MAKEDEP) $(CXXFLAGS) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
|
||||
|
||||
-include $(DEPFILE)
|
||||
|
||||
### Internationalization (I18N):
|
||||
|
||||
PODIR = po
|
||||
I18Npo = $(wildcard $(PODIR)/*.po)
|
||||
I18Nmo = $(addsuffix .mo, $(foreach file, $(I18Npo), $(basename $(file))))
|
||||
I18Nmsgs = $(addprefix $(DESTDIR)$(LOCDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
|
||||
I18Npot = $(PODIR)/$(PLUGIN).pot
|
||||
|
||||
%.mo: %.po
|
||||
msgfmt -c -o $@ $<
|
||||
|
||||
$(I18Npot): $(wildcard *.c)
|
||||
xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
|
||||
|
||||
%.po: $(I18Npot)
|
||||
msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
|
||||
@touch $@
|
||||
|
||||
$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
|
||||
install -D -m644 $< $@
|
||||
|
||||
.PHONY: i18n
|
||||
i18n: $(I18Nmo) $(I18Npot)
|
||||
|
||||
install-i18n: $(I18Nmsgs)
|
||||
|
||||
### Targets:
|
||||
|
||||
$(SOFILE): $(OBJS)
|
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) $(LIBS) -o $@
|
||||
|
||||
install-lib: $(SOFILE)
|
||||
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
|
||||
|
||||
install-themes:
|
||||
mkdir -p $(DESTDIR)$(VDRCONFDIR)/themes
|
||||
cp themes/* $(DESTDIR)$(VDRCONFDIR)/themes
|
||||
|
||||
install-skins:
|
||||
mkdir -p $(DESTDIR)$(PLGRESDIR)/skins
|
||||
cp -r skins/* $(DESTDIR)$(PLGRESDIR)/skins
|
||||
|
||||
install: install-lib install-i18n install-themes install-skins
|
||||
|
||||
dist: $(I18Npo) clean
|
||||
@-rm -rf $(TMPDIR)/$(ARCHIVE)
|
||||
@mkdir $(TMPDIR)/$(ARCHIVE)
|
||||
@cp -a * $(TMPDIR)/$(ARCHIVE)
|
||||
@tar czf $(PACKAGE).tgz --exclude .git* --exclude *.o --exclude *.rej --exclude *.orig -C $(TMPDIR) $(ARCHIVE)
|
||||
@-rm -rf $(TMPDIR)/$(ARCHIVE)
|
||||
@echo Distribution package created as $(PACKAGE).tgz
|
||||
|
||||
clean:
|
||||
@-rm -f $(PODIR)/*.mo $(PODIR)/*.pot
|
||||
@-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~
|
102
README
Normal file
@ -0,0 +1,102 @@
|
||||
This is a "plugin" for the Video Disk Recorder (VDR).
|
||||
|
||||
Written by: Louis Braun <louis DOT braun AT gmx DOT de>
|
||||
|
||||
Project's homepage: http://projects.vdr-developer.org/projects/plg-skindesigner
|
||||
|
||||
Latest version: http://projects.vdr-developer.org/projects/plg-skindesigner/files
|
||||
GIT repository: git clone git://projects.vdr-developer.org/plg-skindesigner.git
|
||||
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
See the file COPYING for more information.
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
Skindesigner is a VDR skin engine that displays XML based Skins.
|
||||
|
||||
Currently two XML Skins (MetrixHD and nOpacity freestyle) are included in
|
||||
<pluginsourcedir>/skins/
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
- VDR version >= 2.0.0
|
||||
|
||||
- Installed ImageMagick or GraphicsMagick for displaying png/jpg Icons, Channel Logos
|
||||
and EPG Images (configurable during make via IMAGELIB = imagemagick|graphicsmagick
|
||||
parameter)
|
||||
|
||||
- libxml2
|
||||
|
||||
- for scaling the video picture to fit into the VDR menu window please use
|
||||
softhddevice plugin revision 87c1c7be (2013-01-01) or newer.
|
||||
|
||||
- epgsearch Git since commit ba7c6277 (2013-01-03) to correctly replace the schedules
|
||||
menu with epgsearch
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
After "normal" Plugin installation you have to care about the paths for the
|
||||
XML skins and epg images. The following paths can be set at startup:
|
||||
|
||||
-s <SKINPATH>, --skinpath=<SKINPATH>
|
||||
Path to the XML skins (Default: <ResourceDirectory>/plugins/skindesigner/skins/)
|
||||
|
||||
-e path, --epgimages=path
|
||||
Path to the epgimages (Default: <CacheDirectory>/epgimages/)
|
||||
|
||||
ResourceDirectory and CacheDirectory are taken from your VDR configuration (make.config
|
||||
or vdr.pc).
|
||||
|
||||
During a "make install" the included skins are automatically copied from
|
||||
<SkinSourceDirectory>/skins/ to the configured path.
|
||||
|
||||
For S2-6400 Users: Disable High Level OSD, otherwise the plugin will not be
|
||||
loaded because lack of true color support
|
||||
|
||||
For Xine-Plugin Users: Set "Blend scaled Auto" as OSD display mode to achieve
|
||||
an suitable true color OSD.
|
||||
|
||||
For Xineliboutput Users: Start vdr-sxfe with the --hud option enabled
|
||||
|
||||
Since the default skin MetrixHD uses VDROpenSans as font which is not installed per
|
||||
default, you may want to install this font (included in <SkinSourceDirectory>/fonts/)
|
||||
first. Otherwise the inside VDRs OSD menu configured vdrOsd Font is used as default.
|
||||
|
||||
Channel Logos
|
||||
-------------
|
||||
|
||||
Since each XML skin is responsible for it's used channel logos, skindesigner searches
|
||||
for channel logos only in the skin dependend directory
|
||||
|
||||
<ResourceDirectory>/plugins/skindesigner/skins/<skinname>/logos
|
||||
|
||||
Each copy your used logos directly to this directory or set a symbolic link to a common
|
||||
channellogo directory.
|
||||
|
||||
I recommend to use channel logos from https://github.com/3PO/Senderlogos
|
||||
To download them just change in the directory you want to place the logos
|
||||
and do a:
|
||||
git clone https://github.com/3PO/Senderlogos.git logos
|
||||
An update of the logos can then be done with a "git pull" just inside this
|
||||
directory.
|
||||
|
||||
In this logo pack all files are named only with lower case letters.
|
||||
Skindesigner uses the channel name CONVERTED TO LOWER CASE LETTERS to search for an
|
||||
appropriate channel logo. With this, approximately 90% of the channel logos should work
|
||||
immediately after placing the channel logos in the correct place. So if you have to change
|
||||
the name of a channel logo (may be by inserting a space or a hyphen) so that it fits to
|
||||
the channel name, only use lower case letters, and not the name of the channel with upper
|
||||
and lower letters as displayed inside VDR.
|
||||
If no logo is found for the channel name, additionally a search for a logo named as the
|
||||
ChannelID is performed. Analog to the channel name the ChannelID is also converted to lower
|
||||
case letters. This allows channel logos for channels with changing names (for instance
|
||||
Sky Feed Channels).
|
||||
Additional hint: some channels have slashes in their name (in germany nick/comedy for instance).
|
||||
In this example, as a dirty hack just create a folder in your channel logo directory named
|
||||
"nick" and place an image named "comedy.png" inside this folder.
|
76
config.c
Normal file
@ -0,0 +1,76 @@
|
||||
#include "config.h"
|
||||
#include "libcore/helpers.h"
|
||||
#include "libcore/imageloader.h"
|
||||
|
||||
cDesignerConfig::cDesignerConfig() {
|
||||
epgImagePathSet = false;
|
||||
skinPathSet = false;
|
||||
//Common
|
||||
logoExtension = "png";
|
||||
numLogosPerSizeInitial = 30;
|
||||
limitLogoCache = 1;
|
||||
numLogosMax = 200;
|
||||
debugImageLoading = 0;
|
||||
//default logo width and height
|
||||
logoWidth = 268;
|
||||
logoHeight = 200;
|
||||
replaceDecPoint = false;
|
||||
}
|
||||
|
||||
cDesignerConfig::~cDesignerConfig() {
|
||||
}
|
||||
|
||||
void cDesignerConfig::SetPathes(void) {
|
||||
if (!skinPathSet)
|
||||
skinPath = cString::sprintf("%s/skins/", cPlugin::ResourceDirectory(PLUGIN_NAME_I18N));
|
||||
if (!epgImagePathSet)
|
||||
epgImagePath = cString::sprintf("%s/epgimages/", cPlugin::CacheDirectory(PLUGIN_NAME_I18N));
|
||||
|
||||
dsyslog("skindesigner: using Skin Directory %s", *skinPath);
|
||||
dsyslog("skindesigner: using EPG Images Directory %s", *epgImagePath);
|
||||
|
||||
}
|
||||
|
||||
void cDesignerConfig::SetSkinPath(cString path) {
|
||||
skinPath = CheckSlashAtEnd(*path);
|
||||
skinPathSet = true;
|
||||
}
|
||||
|
||||
void cDesignerConfig::SetEpgImagePath(cString path) {
|
||||
epgImagePath = CheckSlashAtEnd(*path);
|
||||
epgImagePathSet = true;
|
||||
}
|
||||
|
||||
void cDesignerConfig::SetChannelLogoSize(void) {
|
||||
cImageLoader imgLoader;
|
||||
imgLoader.DeterminateChannelLogoSize(logoWidth, logoHeight);
|
||||
dsyslog("skindesigner: using %dx%d px as original channel logo size", logoWidth, logoHeight);
|
||||
}
|
||||
|
||||
void cDesignerConfig::CheckDecimalPoint(void) {
|
||||
struct lconv *pLocInfo;
|
||||
pLocInfo = localeconv();
|
||||
string decimalPoint = pLocInfo->decimal_point;
|
||||
if (decimalPoint.compare(".")) {
|
||||
dsyslog("skindesigner: using decimal point %s", decimalPoint.c_str());
|
||||
replaceDecPoint = true;
|
||||
decPoint = decimalPoint[0];
|
||||
}
|
||||
}
|
||||
|
||||
cString cDesignerConfig::CheckSlashAtEnd(std::string path) {
|
||||
try {
|
||||
if (!(path.at(path.size()-1) == '/'))
|
||||
return cString::sprintf("%s/", path.c_str());
|
||||
} catch (...) {return path.c_str();}
|
||||
return path.c_str();
|
||||
}
|
||||
|
||||
bool cDesignerConfig::SetupParse(const char *Name, const char *Value) {
|
||||
if (!strcasecmp(Name, "DebugImageLoading")) debugImageLoading = atoi(Value);
|
||||
else if (!strcasecmp(Name, "LimitChannelLogoCache")) limitLogoCache = atoi(Value);
|
||||
else if (!strcasecmp(Name, "NumberLogosInitially")) numLogosPerSizeInitial = atoi(Value);
|
||||
else if (!strcasecmp(Name, "NumberLogosMax")) numLogosMax = atoi(Value);
|
||||
else return false;
|
||||
return true;
|
||||
}
|
53
config.h
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef __DESIGNER_CONFIG_H
|
||||
#define __DESIGNER_CONFIG_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <vdr/tools.h>
|
||||
#include <vdr/skins.h>
|
||||
#include <vdr/plugin.h>
|
||||
#include "libcore/fontmanager.h"
|
||||
#include "libcore/imagecache.h"
|
||||
|
||||
class cDesignerConfig {
|
||||
private:
|
||||
cString CheckSlashAtEnd(std::string path);
|
||||
bool epgImagePathSet;
|
||||
bool skinPathSet;
|
||||
public:
|
||||
cDesignerConfig();
|
||||
~cDesignerConfig();
|
||||
bool SetupParse(const char *Name, const char *Value);
|
||||
void SetSkinPath(cString path);
|
||||
void SetEpgImagePath(cString path);
|
||||
void SetPathes(void);
|
||||
void SetChannelLogoSize(void);
|
||||
void CheckDecimalPoint(void);
|
||||
cString logoExtension;
|
||||
cString skinPath;
|
||||
cString epgImagePath;
|
||||
int numLogosPerSizeInitial;
|
||||
int limitLogoCache;
|
||||
int numLogosMax;
|
||||
int debugImageLoading;
|
||||
int logoWidth;
|
||||
int logoHeight;
|
||||
bool replaceDecPoint;
|
||||
char decPoint;
|
||||
};
|
||||
#ifdef DEFINE_CONFIG
|
||||
bool firstDisplay = true;
|
||||
cDesignerConfig config;
|
||||
cFontManager *fontManager;
|
||||
cImageCache *imgCache;
|
||||
cTheme Theme;
|
||||
#else
|
||||
extern bool firstDisplay;
|
||||
extern cDesignerConfig config;
|
||||
extern cFontManager *fontManager;
|
||||
extern cImageCache *imgCache;
|
||||
extern cTheme Theme;
|
||||
#endif
|
||||
|
||||
#endif //__DESIGNER_CONFIG_H
|
309
designer.c
Normal file
@ -0,0 +1,309 @@
|
||||
#include "designer.h"
|
||||
#include "libcore/helpers.h"
|
||||
|
||||
cSkinDesigner::cSkinDesigner(void) : cSkin("skindesigner", &::Theme) {
|
||||
backupSkin = NULL;
|
||||
useBackupSkin = false;
|
||||
|
||||
SetOSDSize();
|
||||
osdTheme = Setup.OSDTheme;
|
||||
config.SetPathes();
|
||||
config.SetChannelLogoSize();
|
||||
config.CheckDecimalPoint();
|
||||
fontManager = new cFontManager();
|
||||
imgCache = new cImageCache();
|
||||
|
||||
globals = NULL;
|
||||
channelTemplate = NULL;
|
||||
menuTemplate = NULL;
|
||||
messageTemplate = NULL;
|
||||
replayTemplate = NULL;
|
||||
volumeTemplate = NULL;
|
||||
audiotracksTemplate = NULL;
|
||||
|
||||
cStopWatch watch;
|
||||
bool ok = LoadTemplates();
|
||||
if (!ok) {
|
||||
esyslog("skindesigner: error during loading of templates - using LCARS as backup");
|
||||
backupSkin = new cSkinLCARS();
|
||||
useBackupSkin = true;
|
||||
} else {
|
||||
CacheTemplates();
|
||||
watch.Stop("templates loaded and cache created");
|
||||
}
|
||||
}
|
||||
|
||||
cSkinDesigner::~cSkinDesigner(void) {
|
||||
if (globals)
|
||||
delete globals;
|
||||
DeleteTemplates();
|
||||
if (backupSkin)
|
||||
delete backupSkin;
|
||||
}
|
||||
|
||||
const char *cSkinDesigner::Description(void) {
|
||||
return "SkinDesigner";
|
||||
}
|
||||
|
||||
cSkinDisplayChannel *cSkinDesigner::DisplayChannel(bool WithInfo) {
|
||||
cSkinDisplayChannel *displayChannel = NULL;
|
||||
if (!useBackupSkin) {
|
||||
ReloadCaches();
|
||||
displayChannel = new cSDDisplayChannel(channelTemplate, WithInfo);
|
||||
} else {
|
||||
displayChannel = backupSkin->DisplayChannel(WithInfo);
|
||||
}
|
||||
return displayChannel;
|
||||
}
|
||||
|
||||
cSkinDisplayMenu *cSkinDesigner::DisplayMenu(void) {
|
||||
cSkinDisplayMenu *displayMenu = NULL;
|
||||
if (!useBackupSkin) {
|
||||
ReloadCaches();
|
||||
displayMenu = new cSDDisplayMenu(menuTemplate);
|
||||
} else {
|
||||
displayMenu = backupSkin->DisplayMenu();
|
||||
}
|
||||
return displayMenu;
|
||||
}
|
||||
|
||||
cSkinDisplayReplay *cSkinDesigner::DisplayReplay(bool ModeOnly) {
|
||||
cSkinDisplayReplay *displayReplay = NULL;
|
||||
if (!useBackupSkin) {
|
||||
ReloadCaches();
|
||||
displayReplay = new cSDDisplayReplay(replayTemplate, ModeOnly);
|
||||
} else {
|
||||
displayReplay = backupSkin->DisplayReplay(ModeOnly);
|
||||
}
|
||||
return displayReplay;
|
||||
}
|
||||
|
||||
cSkinDisplayVolume *cSkinDesigner::DisplayVolume(void) {
|
||||
cSkinDisplayVolume *displayVolume = NULL;
|
||||
if (!useBackupSkin) {
|
||||
ReloadCaches();
|
||||
displayVolume = new cSDDisplayVolume(volumeTemplate);
|
||||
} else {
|
||||
displayVolume = backupSkin->DisplayVolume();
|
||||
}
|
||||
return displayVolume;
|
||||
}
|
||||
|
||||
cSkinDisplayTracks *cSkinDesigner::DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks) {
|
||||
cSkinDisplayTracks *displayTracks = NULL;
|
||||
if (!useBackupSkin) {
|
||||
ReloadCaches();
|
||||
displayTracks = new cSDDisplayTracks(audiotracksTemplate, Title, NumTracks, Tracks);
|
||||
} else {
|
||||
displayTracks = backupSkin->DisplayTracks(Title, NumTracks, Tracks);
|
||||
}
|
||||
return displayTracks;
|
||||
}
|
||||
|
||||
cSkinDisplayMessage *cSkinDesigner::DisplayMessage(void) {
|
||||
cSkinDisplayMessage *displayMessage = NULL;
|
||||
if (!useBackupSkin) {
|
||||
ReloadCaches();
|
||||
displayMessage = new cSDDisplayMessage(messageTemplate);
|
||||
} else {
|
||||
displayMessage = backupSkin->DisplayMessage();
|
||||
}
|
||||
return displayMessage;
|
||||
}
|
||||
|
||||
void cSkinDesigner::Reload(void) {
|
||||
dsyslog("skindesigner: forcing full reload of templates");
|
||||
if (cOsd::IsOpen()) {
|
||||
esyslog("skindesigner: OSD is open, close first!");
|
||||
return;
|
||||
}
|
||||
DeleteTemplates();
|
||||
cStopWatch watch;
|
||||
bool ok = LoadTemplates();
|
||||
if (!ok) {
|
||||
esyslog("skindesigner: error during loading of templates - using LCARS as backup");
|
||||
if (!backupSkin)
|
||||
backupSkin = new cSkinLCARS();
|
||||
useBackupSkin = true;
|
||||
} else {
|
||||
CacheTemplates();
|
||||
useBackupSkin = false;
|
||||
watch.Stop("templates reloaded and cache created");
|
||||
}
|
||||
}
|
||||
|
||||
void cSkinDesigner::ListAvailableFonts(void) {
|
||||
fontManager->ListAvailableFonts();
|
||||
}
|
||||
|
||||
/*********************************************************************************
|
||||
* PRIVATE FUNCTIONS
|
||||
*********************************************************************************/
|
||||
void cSkinDesigner::DeleteTemplates(void) {
|
||||
if (channelTemplate) {
|
||||
delete channelTemplate;
|
||||
channelTemplate = NULL;
|
||||
}
|
||||
if (menuTemplate) {
|
||||
delete menuTemplate;
|
||||
menuTemplate = NULL;
|
||||
}
|
||||
if (messageTemplate) {
|
||||
delete messageTemplate;
|
||||
messageTemplate = NULL;
|
||||
}
|
||||
if (replayTemplate) {
|
||||
delete replayTemplate;
|
||||
replayTemplate = NULL;
|
||||
}
|
||||
if (volumeTemplate) {
|
||||
delete volumeTemplate;
|
||||
volumeTemplate = NULL;
|
||||
}
|
||||
if (audiotracksTemplate) {
|
||||
delete audiotracksTemplate;
|
||||
audiotracksTemplate = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool cSkinDesigner::LoadTemplates(void) {
|
||||
|
||||
globals = new cGlobals();
|
||||
bool ok = globals->ReadFromXML();
|
||||
if (!ok) {
|
||||
esyslog("skindesigner: error parsing globals, aborting");
|
||||
return false;
|
||||
}
|
||||
//globals->Debug();
|
||||
|
||||
DeleteTemplates();
|
||||
|
||||
channelTemplate = new cTemplate(vtDisplayChannel);
|
||||
channelTemplate->SetGlobals(globals);
|
||||
ok = channelTemplate->ReadFromXML();
|
||||
if (!ok) {
|
||||
esyslog("skindesigner: error reading displaychannel template, aborting");
|
||||
DeleteTemplates();
|
||||
return false;
|
||||
}
|
||||
channelTemplate->Translate();
|
||||
|
||||
menuTemplate = new cTemplate(vtDisplayMenu);
|
||||
menuTemplate->SetGlobals(globals);
|
||||
ok = menuTemplate->ReadFromXML();
|
||||
if (!ok) {
|
||||
esyslog("skindesigner: error reading displaymenu template, aborting");
|
||||
DeleteTemplates();
|
||||
return false;
|
||||
}
|
||||
menuTemplate->Translate();
|
||||
|
||||
messageTemplate = new cTemplate(vtDisplayMessage);
|
||||
messageTemplate->SetGlobals(globals);
|
||||
ok = messageTemplate->ReadFromXML();
|
||||
if (!ok) {
|
||||
esyslog("skindesigner: error reading displaymessage template, aborting");
|
||||
DeleteTemplates();
|
||||
return false;
|
||||
}
|
||||
messageTemplate->Translate();
|
||||
|
||||
replayTemplate = new cTemplate(vtDisplayReplay);
|
||||
replayTemplate->SetGlobals(globals);
|
||||
ok = replayTemplate->ReadFromXML();
|
||||
if (!ok) {
|
||||
esyslog("skindesigner: error reading displayreplay template, aborting");
|
||||
DeleteTemplates();
|
||||
return false;
|
||||
}
|
||||
replayTemplate->Translate();
|
||||
|
||||
volumeTemplate = new cTemplate(vtDisplayVolume);
|
||||
volumeTemplate->SetGlobals(globals);
|
||||
ok = volumeTemplate->ReadFromXML();
|
||||
if (!ok) {
|
||||
esyslog("skindesigner: error reading displayvolume template, aborting");
|
||||
DeleteTemplates();
|
||||
return false;
|
||||
}
|
||||
volumeTemplate->Translate();
|
||||
|
||||
audiotracksTemplate = new cTemplate(vtDisplayAudioTracks);
|
||||
audiotracksTemplate->SetGlobals(globals);
|
||||
ok = audiotracksTemplate->ReadFromXML();
|
||||
if (!ok) {
|
||||
esyslog("skindesigner: error reading displayaudiotracks template, aborting");
|
||||
DeleteTemplates();
|
||||
return false;
|
||||
}
|
||||
audiotracksTemplate->Translate();
|
||||
|
||||
dsyslog("skindesigner: templates successfully validated and parsed");
|
||||
return true;
|
||||
}
|
||||
|
||||
void cSkinDesigner::CacheTemplates(void) {
|
||||
channelTemplate->PreCache();
|
||||
menuTemplate->PreCache();
|
||||
messageTemplate->PreCache();
|
||||
replayTemplate->PreCache();
|
||||
volumeTemplate->PreCache();
|
||||
audiotracksTemplate->PreCache();
|
||||
dsyslog("skindesigner: templates cached");
|
||||
fontManager->CacheFonts(channelTemplate);
|
||||
fontManager->CacheFonts(menuTemplate);
|
||||
fontManager->CacheFonts(messageTemplate);
|
||||
fontManager->CacheFonts(replayTemplate);
|
||||
fontManager->CacheFonts(volumeTemplate);
|
||||
fontManager->CacheFonts(audiotracksTemplate);
|
||||
dsyslog("skindesigner: fonts cached");
|
||||
dsyslog("skindesigner: caching images...");
|
||||
imgCache->Clear();
|
||||
channelTemplate->CacheImages();
|
||||
menuTemplate->CacheImages();
|
||||
messageTemplate->CacheImages();
|
||||
replayTemplate->CacheImages();
|
||||
volumeTemplate->CacheImages();
|
||||
audiotracksTemplate->CacheImages();
|
||||
imgCache->Debug(false);
|
||||
}
|
||||
|
||||
void cSkinDesigner::ReloadCaches(void) {
|
||||
if (OsdSizeChanged() || ThemeChanged()) {
|
||||
cStopWatch watch;
|
||||
bool ok = LoadTemplates();
|
||||
if (ok) {
|
||||
CacheTemplates();
|
||||
}
|
||||
watch.Stop("templates reloaded and cache recreated");
|
||||
}
|
||||
}
|
||||
|
||||
void cSkinDesigner::SetOSDSize(void) {
|
||||
osdSize.SetWidth(cOsd::OsdWidth());
|
||||
osdSize.SetHeight(cOsd::OsdHeight());
|
||||
osdSize.SetX(cOsd::OsdLeft());
|
||||
osdSize.SetY(cOsd::OsdTop());
|
||||
}
|
||||
|
||||
bool cSkinDesigner::OsdSizeChanged(void) {
|
||||
if ((osdSize.Width() != cOsd::OsdWidth()) ||
|
||||
(osdSize.Height() != cOsd::OsdHeight()) ||
|
||||
(osdSize.X() != cOsd::OsdLeft()) ||
|
||||
(osdSize.Y() != cOsd::OsdTop())) {
|
||||
dsyslog("skindesigner: osd size changed");
|
||||
dsyslog("skindesigner: old osd size: top %d left %d size %d * %d", osdSize.X(), osdSize.Y(), osdSize.Width(), osdSize.Height());
|
||||
SetOSDSize();
|
||||
dsyslog("skindesigner: new osd size: top %d left %d size %d * %d", osdSize.X(), osdSize.Y(), osdSize.Width(), osdSize.Height());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cSkinDesigner::ThemeChanged(void) {
|
||||
if (osdTheme.compare(Setup.OSDTheme) != 0) {
|
||||
osdTheme = Setup.OSDTheme;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
49
designer.h
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef __SKINDESIGNER_H
|
||||
#define __SKINDESIGNER_H
|
||||
|
||||
#include "config.h"
|
||||
#include "libtemplate/template.h"
|
||||
#include "libtemplate/xmlparser.h"
|
||||
#include "displaychannel.h"
|
||||
#include "displaymenu.h"
|
||||
#include "displayreplay.h"
|
||||
#include "displayvolume.h"
|
||||
#include "displaytracks.h"
|
||||
#include "displaymessage.h"
|
||||
#include <vdr/skinlcars.h>
|
||||
|
||||
class cSkinDesigner : public cSkin {
|
||||
private:
|
||||
cSkinLCARS *backupSkin;
|
||||
bool useBackupSkin;
|
||||
cRect osdSize;
|
||||
std::string osdTheme;
|
||||
cGlobals *globals;
|
||||
cTemplate *channelTemplate;
|
||||
cTemplate *menuTemplate;
|
||||
cTemplate *messageTemplate;
|
||||
cTemplate *replayTemplate;
|
||||
cTemplate *volumeTemplate;
|
||||
cTemplate *audiotracksTemplate;
|
||||
void DeleteTemplates(void);
|
||||
void ReloadCaches(void);
|
||||
bool LoadTemplates(void);
|
||||
void CacheTemplates(void);
|
||||
void SetOSDSize(void);
|
||||
bool OsdSizeChanged(void);
|
||||
bool ThemeChanged(void);
|
||||
public:
|
||||
cSkinDesigner(void);
|
||||
virtual ~cSkinDesigner(void);
|
||||
virtual const char *Description(void);
|
||||
virtual cSkinDisplayChannel *DisplayChannel(bool WithInfo);
|
||||
virtual cSkinDisplayMenu *DisplayMenu(void);
|
||||
virtual cSkinDisplayReplay *DisplayReplay(bool ModeOnly);
|
||||
virtual cSkinDisplayVolume *DisplayVolume(void);
|
||||
virtual cSkinDisplayTracks *DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks);
|
||||
virtual cSkinDisplayMessage *DisplayMessage(void);
|
||||
void Reload(void);
|
||||
void ListAvailableFonts(void);
|
||||
};
|
||||
|
||||
#endif //__SKINDESIGNER_H
|
193
displaychannel.c
Normal file
@ -0,0 +1,193 @@
|
||||
#include "displaychannel.h"
|
||||
#include "libcore/timers.h"
|
||||
|
||||
cSDDisplayChannel::cSDDisplayChannel(cTemplate *channelTemplate, bool WithInfo) {
|
||||
if (firstDisplay) {
|
||||
firstDisplay = false;
|
||||
doOutput = false;
|
||||
return;
|
||||
} else if (!channelTemplate) {
|
||||
esyslog("skindesigner: displayChannel no valid template - aborting");
|
||||
doOutput = false;
|
||||
return;
|
||||
} else {
|
||||
doOutput = true;
|
||||
}
|
||||
groupSep = false;
|
||||
present = NULL;
|
||||
currentLast = 0;
|
||||
channelChange = false;
|
||||
initial = true;
|
||||
|
||||
channelView = new cDisplayChannelView(channelTemplate->GetRootView());
|
||||
if (!channelView->createOsd()) {
|
||||
doOutput = false;
|
||||
return;
|
||||
}
|
||||
channelView->DrawBackground();
|
||||
channelView->DrawSignalBackground();
|
||||
}
|
||||
|
||||
cSDDisplayChannel::~cSDDisplayChannel() {
|
||||
if (!doOutput)
|
||||
return;
|
||||
delete channelView;
|
||||
}
|
||||
|
||||
void cSDDisplayChannel::SetChannel(const cChannel *Channel, int Number) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
|
||||
channelChange = true;
|
||||
groupSep = false;
|
||||
|
||||
cString ChannelNumber("");
|
||||
cString ChannelName("");
|
||||
cString ChannelID("");
|
||||
|
||||
if (Channel) {
|
||||
ChannelName = Channel->Name();
|
||||
ChannelID = Channel->GetChannelID().ToString();
|
||||
if (!Channel->GroupSep()) {
|
||||
ChannelNumber = cString::sprintf("%d%s", Channel->Number(), Number ? "-" : "");
|
||||
} else {
|
||||
groupSep = true;
|
||||
}
|
||||
} else if (Number) {
|
||||
ChannelNumber = cString::sprintf("%d-", Number);
|
||||
} else {
|
||||
ChannelName = ChannelString(NULL, 0);
|
||||
}
|
||||
channelView->ClearChannel();
|
||||
channelView->ClearEPGInfo();
|
||||
channelView->ClearStatusIcons();
|
||||
channelView->ClearChannelGroups();
|
||||
channelView->ClearScraperContent();
|
||||
if (!groupSep) {
|
||||
channelView->DrawChannel(ChannelNumber, ChannelName, ChannelID, (Number > 0)?true:false);
|
||||
channelView->DrawProgressBarBack();
|
||||
channelView->DrawSignalBackground();
|
||||
if (Channel)
|
||||
channelView->DrawStatusIcons(Channel);
|
||||
} else {
|
||||
channelView->ClearSignal();
|
||||
channelView->ClearSignalBackground();
|
||||
channelView->ClearProgressBar();
|
||||
channelView->ClearProgressBarBack();
|
||||
if (Channel)
|
||||
channelView->DrawChannelGroups(Channel, ChannelName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void cSDDisplayChannel::SetEvents(const cEvent *Present, const cEvent *Following) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
|
||||
present = Present;
|
||||
channelView->ClearProgressBar();
|
||||
if (!groupSep) {
|
||||
channelView->ClearEPGInfo();
|
||||
}
|
||||
|
||||
cGlobalSortedTimers SortedTimers;// local and remote timers
|
||||
|
||||
bool recPresent = false;
|
||||
if (Present) {
|
||||
if (!groupSep) {
|
||||
SetProgressBar(Present);
|
||||
}
|
||||
eTimerMatch TimerMatch = tmNone;
|
||||
const cTimer *Timer = Timers.GetMatch(Present, &TimerMatch);
|
||||
if (Timer && Timer->Recording()) {
|
||||
recPresent = true;
|
||||
}
|
||||
for (int i = 0; i < SortedTimers.Size() && !recPresent; i++)
|
||||
if (const cTimer *Timer = SortedTimers[i])
|
||||
if (Timer->Channel()->GetChannelID() == Present->ChannelID())
|
||||
if (const cEvent *timerEvent = Timer->Event())
|
||||
if (Present->EventID() == timerEvent->EventID())
|
||||
recPresent = Timer->Recording();
|
||||
|
||||
}
|
||||
bool recFollowing = false;
|
||||
if (Following) {
|
||||
recFollowing = Following->HasTimer();
|
||||
for (int i = 0; i < SortedTimers.Size() && !recFollowing; i++)
|
||||
if (const cTimer *Timer = SortedTimers[i])
|
||||
if (Timer->Channel()->GetChannelID() == Following->ChannelID())
|
||||
if (const cEvent *timerEvent = Timer->Event())
|
||||
if (Following->EventID() == timerEvent->EventID())
|
||||
recFollowing = true;
|
||||
}
|
||||
|
||||
if (Present || Following) {
|
||||
channelView->DrawEPGInfo(Present, Following, recPresent, recFollowing);
|
||||
channelView->DrawScraperContent(Present);
|
||||
}
|
||||
}
|
||||
|
||||
void cSDDisplayChannel::SetProgressBar(const cEvent *present) {
|
||||
int Current = 0;
|
||||
int Total = 0;
|
||||
time_t t = time(NULL);
|
||||
if (t > present->StartTime())
|
||||
Current = t - present->StartTime();
|
||||
Total = present->Duration();
|
||||
if ((Current > currentLast + 3) || initial || channelChange) {
|
||||
currentLast = Current;
|
||||
cString start = present->GetTimeString();
|
||||
cString stop = present->GetEndTimeString();
|
||||
channelView->DrawProgressBar(start, stop, Current, Total);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void cSDDisplayChannel::SetMessage(eMessageType Type, const char *Text) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
channelView->ClearChannel();
|
||||
channelView->ClearEPGInfo();
|
||||
channelView->ClearStatusIcons();
|
||||
channelView->ClearScreenResolution();
|
||||
channelView->ClearProgressBar();
|
||||
channelView->ClearProgressBarBack();
|
||||
channelView->ClearSignal();
|
||||
channelView->ClearSignalBackground();
|
||||
channelView->ClearScraperContent();
|
||||
channelView->DisplayMessage(Type, Text);
|
||||
groupSep = true;
|
||||
}
|
||||
|
||||
void cSDDisplayChannel::Flush(void) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
|
||||
if (initial || channelChange) {
|
||||
channelView->DrawDate();
|
||||
}
|
||||
|
||||
if (present) {
|
||||
SetProgressBar(present);
|
||||
} else {
|
||||
channelView->ClearProgressBar();
|
||||
}
|
||||
|
||||
if (!groupSep) {
|
||||
channelView->DrawScreenResolution();
|
||||
channelView->DrawSignal();
|
||||
} else {
|
||||
channelView->ClearStatusIcons();
|
||||
channelView->ClearScreenResolution();
|
||||
channelView->ClearSignal();
|
||||
channelView->ClearSignalBackground();
|
||||
}
|
||||
|
||||
if (initial) {
|
||||
channelView->DoStart();
|
||||
}
|
||||
|
||||
initial = false;
|
||||
channelChange = false;
|
||||
channelView->Flush();
|
||||
}
|
32
displaychannel.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef __DISPLAYCHANNEL_H
|
||||
#define __DISPLAYCHANNEL_H
|
||||
|
||||
#include <vdr/thread.h>
|
||||
#include "config.h"
|
||||
#include "libtemplate/template.h"
|
||||
#include "views/displaychannelview.h"
|
||||
|
||||
class cSDDisplayChannel : public cSkinDisplayChannel {
|
||||
private:
|
||||
cDisplayChannelView *channelView;
|
||||
bool doOutput;
|
||||
bool initial;
|
||||
bool groupSep;
|
||||
bool channelChange;
|
||||
time_t lastSignalDisplay;
|
||||
int lastSignalStrength;
|
||||
int lastSignalQuality;
|
||||
int lastScreenWidth;
|
||||
int currentLast;
|
||||
bool showSignal;
|
||||
const cEvent *present;
|
||||
void SetProgressBar(const cEvent *present);
|
||||
public:
|
||||
cSDDisplayChannel(cTemplate *channelTemplate, bool WithInfo);
|
||||
virtual ~cSDDisplayChannel();
|
||||
virtual void SetChannel(const cChannel *Channel, int Number);
|
||||
virtual void SetEvents(const cEvent *Present, const cEvent *Following);
|
||||
virtual void SetMessage(eMessageType Type, const char *Text);
|
||||
virtual void Flush(void);
|
||||
};
|
||||
#endif //__DISPLAYCHANNEL_H
|
233
displaymenu.c
Normal file
@ -0,0 +1,233 @@
|
||||
#include "displaymenu.h"
|
||||
#include "libcore/helpers.h"
|
||||
|
||||
cSDDisplayMenu::cSDDisplayMenu(cTemplate *menuTemplate) {
|
||||
doOutput = true;
|
||||
state = vsInit;
|
||||
if (!menuTemplate) {
|
||||
doOutput = false;
|
||||
esyslog("skindesigner: displayMenu no valid template - aborting");
|
||||
return;
|
||||
}
|
||||
rootView = new cDisplayMenuRootView(menuTemplate->GetRootView());
|
||||
if (!rootView->createOsd()) {
|
||||
doOutput = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cSDDisplayMenu::~cSDDisplayMenu() {
|
||||
if (!doOutput)
|
||||
return;
|
||||
delete rootView;
|
||||
}
|
||||
|
||||
void cSDDisplayMenu::Scroll(bool Up, bool Page) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
rootView->KeyInput(Up, Page);
|
||||
}
|
||||
|
||||
int cSDDisplayMenu::MaxItems(void) {
|
||||
if (!doOutput)
|
||||
return 0;
|
||||
int maxItems = rootView->GetMaxItems();
|
||||
return maxItems;
|
||||
}
|
||||
|
||||
void cSDDisplayMenu::Clear(void) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
rootView->Clear();
|
||||
}
|
||||
|
||||
void cSDDisplayMenu::SetMenuCategory(eMenuCategory MenuCat) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
rootView->SetMenu(MenuCat, (state == vsInit) ? true : false);
|
||||
cSkinDisplayMenu::SetMenuCategory(MenuCat);
|
||||
if (state != vsInit)
|
||||
state = vsMenuInit;
|
||||
}
|
||||
|
||||
void cSDDisplayMenu::SetTitle(const char *Title) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
rootView->SetTitle(Title);
|
||||
}
|
||||
|
||||
void cSDDisplayMenu::SetButtons(const char *Red, const char *Green, const char *Yellow, const char *Blue) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
rootView->SetButtonTexts(Red, Green, Yellow, Blue);
|
||||
if (state != vsInit && MenuCategory() != mcMain)
|
||||
state = vsMenuInit;
|
||||
}
|
||||
|
||||
void cSDDisplayMenu::SetMessage(eMessageType Type, const char *Text) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
rootView->SetMessage(Type, Text);
|
||||
rootView->DoFlush();
|
||||
}
|
||||
|
||||
bool cSDDisplayMenu::SetItemEvent(const cEvent *Event, int Index, bool Current, bool Selectable, const cChannel *Channel, bool WithDate, eTimerMatch TimerMatch) {
|
||||
if (!doOutput)
|
||||
return true;
|
||||
if (!rootView->SubViewAvailable())
|
||||
return false;
|
||||
if (Current) {
|
||||
if (Channel) {
|
||||
rootView->SetChannel(Channel);
|
||||
} else if (Event) {
|
||||
rootView->SetChannel(Channels.GetByChannelID(Event->ChannelID()));
|
||||
}
|
||||
}
|
||||
cDisplayMenuListView *list = rootView->GetListView();
|
||||
if (!list)
|
||||
return false;
|
||||
list->AddSchedulesMenuItem(Index, Event, Channel, TimerMatch, MenuCategory(), Current, Selectable);
|
||||
if (state == vsIdle)
|
||||
state = vsMenuUpdate;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cSDDisplayMenu::SetItemTimer(const cTimer *Timer, int Index, bool Current, bool Selectable) {
|
||||
if (!doOutput)
|
||||
return true;
|
||||
if (!rootView->SubViewAvailable())
|
||||
return false;
|
||||
cDisplayMenuListView *list = rootView->GetListView();
|
||||
if (!list)
|
||||
return false;
|
||||
list->AddTimersMenuItem(Index, Timer, Current, Selectable);
|
||||
if (state == vsIdle)
|
||||
state = vsMenuUpdate;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cSDDisplayMenu::SetItemChannel(const cChannel *Channel, int Index, bool Current, bool Selectable, bool WithProvider) {
|
||||
if (!doOutput)
|
||||
return true;
|
||||
if (!rootView->SubViewAvailable())
|
||||
return false;
|
||||
cDisplayMenuListView *list = rootView->GetListView();
|
||||
if (!list)
|
||||
return false;
|
||||
list->AddChannelsMenuItem(Index, Channel, WithProvider, Current, Selectable);
|
||||
if (state == vsIdle)
|
||||
state = vsMenuUpdate;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cSDDisplayMenu::SetItemRecording(const cRecording *Recording, int Index, bool Current, bool Selectable, int Level, int Total, int New) {
|
||||
if (!doOutput)
|
||||
return true;
|
||||
if (!rootView->SubViewAvailable())
|
||||
return false;
|
||||
cDisplayMenuListView *list = rootView->GetListView();
|
||||
if (!list)
|
||||
return false;
|
||||
list->AddRecordingMenuItem(Index, Recording, Level, Total, New, Current, Selectable);
|
||||
if (state == vsIdle)
|
||||
state = vsMenuUpdate;
|
||||
return true;
|
||||
}
|
||||
|
||||
void cSDDisplayMenu::SetItem(const char *Text, int Index, bool Current, bool Selectable) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
cDisplayMenuListView *list = rootView->GetListView();
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
eMenuCategory cat = MenuCategory();
|
||||
if (cat == mcMain) {
|
||||
list->AddMainMenuItem(Index, Text, Current, Selectable);
|
||||
} else if (cat == mcSetup) {
|
||||
list->AddSetupMenuItem(Index, Text, Current, Selectable);
|
||||
} else {
|
||||
string *tabTexts = new string[MaxTabs];
|
||||
for (int i=0; i<MaxTabs; i++) {
|
||||
const char *s = GetTabbedText(Text, i);
|
||||
if (s) {
|
||||
tabTexts[i] = s;
|
||||
} else {
|
||||
tabTexts[i] = "";
|
||||
}
|
||||
}
|
||||
list->AddDefaultMenuItem(Index, tabTexts, Current, Selectable);
|
||||
SetEditableWidth( rootView->GetListViewWidth() / 2);
|
||||
}
|
||||
if (state == vsIdle)
|
||||
state = vsMenuUpdate;
|
||||
}
|
||||
|
||||
void cSDDisplayMenu::SetTabs(int Tab1, int Tab2, int Tab3, int Tab4, int Tab5) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
rootView->SetTabs(Tab1, Tab2, Tab3, Tab4, Tab5);
|
||||
}
|
||||
|
||||
int cSDDisplayMenu::GetTextAreaWidth(void) const {
|
||||
int areaWidth = rootView->GetTextAreaWidth();
|
||||
return areaWidth;
|
||||
}
|
||||
|
||||
const cFont *cSDDisplayMenu::GetTextAreaFont(bool FixedFont) const {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void cSDDisplayMenu::SetScrollbar(int Total, int Offset) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
rootView->RenderMenuScrollBar(Total, Offset);
|
||||
}
|
||||
|
||||
void cSDDisplayMenu::SetEvent(const cEvent *Event) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
rootView->SetDetailedViewEvent(Event);
|
||||
state = vsMenuDetail;
|
||||
}
|
||||
|
||||
void cSDDisplayMenu::SetRecording(const cRecording *Recording) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
rootView->SetDetailedViewRecording(Recording);
|
||||
state = vsMenuDetail;
|
||||
}
|
||||
|
||||
void cSDDisplayMenu::SetText(const char *Text, bool FixedFont) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
rootView->SetDetailedViewText(Text);
|
||||
state = vsMenuDetail;
|
||||
}
|
||||
|
||||
void cSDDisplayMenu::Flush(void) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
if (state == vsInit) {
|
||||
rootView->Start();
|
||||
rootView->RenderMenuItems();
|
||||
rootView->DoFlush();
|
||||
} else if (state == vsMenuInit) {
|
||||
rootView->Render();
|
||||
rootView->DoFlush();
|
||||
rootView->RenderMenuItems();
|
||||
rootView->DoFlush();
|
||||
} else if (state == vsMenuUpdate) {
|
||||
rootView->RenderMenuItems();
|
||||
rootView->DoFlush();
|
||||
} else if (state == vsMenuDetail) {
|
||||
rootView->Render();
|
||||
rootView->DoFlush();
|
||||
rootView->RenderDetailView();
|
||||
rootView->DoFlush();
|
||||
} else {
|
||||
if (rootView->RenderDynamicElements())
|
||||
rootView->DoFlush();
|
||||
}
|
||||
state = vsIdle;
|
||||
}
|
48
displaymenu.h
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef __DISPLAYMENU_H
|
||||
#define __DISPLAYMENU_H
|
||||
|
||||
#include "designer.h"
|
||||
#include "libtemplate/template.h"
|
||||
#include "views/displaymenurootview.h"
|
||||
|
||||
enum eViewState {
|
||||
vsInit,
|
||||
vsMenuInit,
|
||||
vsMenuUpdate,
|
||||
vsMenuDetail,
|
||||
vsIdle
|
||||
};
|
||||
|
||||
class cSDDisplayMenu : public cSkinDisplayMenu {
|
||||
private:
|
||||
cDisplayMenuRootView *rootView;
|
||||
eViewState state;
|
||||
bool doOutput;
|
||||
protected:
|
||||
int Tab(int n);
|
||||
public:
|
||||
cSDDisplayMenu(cTemplate *menuTemplate);
|
||||
virtual ~cSDDisplayMenu();
|
||||
virtual void Scroll(bool Up, bool Page);
|
||||
virtual int MaxItems(void);
|
||||
virtual void Clear(void);
|
||||
virtual void SetMenuCategory(eMenuCategory MenuCat);
|
||||
virtual void SetTitle(const char *Title);
|
||||
virtual void SetButtons(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL);
|
||||
virtual void SetMessage(eMessageType Type, const char *Text);
|
||||
virtual void SetItem(const char *Text, int Index, bool Current, bool Selectable);
|
||||
virtual bool SetItemEvent(const cEvent *Event, int Index, bool Current, bool Selectable, const cChannel *Channel, bool WithDate, eTimerMatch TimerMatch);
|
||||
virtual bool SetItemTimer(const cTimer *Timer, int Index, bool Current, bool Selectable);
|
||||
virtual bool SetItemChannel(const cChannel *Channel, int Index, bool Current, bool Selectable, bool WithProvider);
|
||||
virtual bool SetItemRecording(const cRecording *Recording, int Index, bool Current, bool Selectable, int Level, int Total, int New);
|
||||
virtual void SetScrollbar(int Total, int Offset);
|
||||
virtual void SetEvent(const cEvent *Event);
|
||||
virtual void SetRecording(const cRecording *Recording);
|
||||
virtual void SetText(const char *Text, bool FixedFont);
|
||||
virtual void Flush(void);
|
||||
virtual void SetTabs(int Tab1, int Tab2 = 0, int Tab3 = 0, int Tab4 = 0, int Tab5 = 0);
|
||||
virtual int GetTextAreaWidth(void) const;
|
||||
virtual const cFont *GetTextAreaFont(bool FixedFont) const;
|
||||
};
|
||||
|
||||
#endif //__DISPLAYMENU_H
|
43
displaymessage.c
Normal file
@ -0,0 +1,43 @@
|
||||
#include "displaymessage.h"
|
||||
|
||||
cSDDisplayMessage::cSDDisplayMessage(cTemplate *messageTemplate) {
|
||||
doOutput = true;
|
||||
initial = true;
|
||||
if (!messageTemplate) {
|
||||
doOutput = false;
|
||||
esyslog("skindesigner: displayMessage no valid template - aborting");
|
||||
return;
|
||||
}
|
||||
messageView = new cDisplayMessageView(messageTemplate->GetRootView());
|
||||
if (!messageView->createOsd()) {
|
||||
doOutput = false;
|
||||
return;
|
||||
}
|
||||
messageView->DrawBackground();
|
||||
}
|
||||
|
||||
cSDDisplayMessage::~cSDDisplayMessage() {
|
||||
if (!doOutput)
|
||||
return;
|
||||
delete messageView;
|
||||
}
|
||||
|
||||
void cSDDisplayMessage::SetMessage(eMessageType Type, const char *Text) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
if (!Text)
|
||||
return;
|
||||
messageView->DrawMessage(Type, Text);
|
||||
}
|
||||
|
||||
|
||||
void cSDDisplayMessage::Flush(void) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
if (initial) {
|
||||
messageView->DoFadeIn();
|
||||
initial = false;
|
||||
} else {
|
||||
messageView->Flush();
|
||||
}
|
||||
}
|
22
displaymessage.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef __DISPLAYMESSAGE_H
|
||||
#define __DISPLAYMESSAGE_H
|
||||
|
||||
#include <vdr/thread.h>
|
||||
#include <vdr/skins.h>
|
||||
#include "config.h"
|
||||
#include "libtemplate/template.h"
|
||||
#include "views/displaymessageview.h"
|
||||
|
||||
class cSDDisplayMessage : public cSkinDisplayMessage {
|
||||
private:
|
||||
cDisplayMessageView *messageView;
|
||||
bool doOutput;
|
||||
bool initial;
|
||||
public:
|
||||
cSDDisplayMessage(cTemplate *messageTemplate);
|
||||
virtual ~cSDDisplayMessage();
|
||||
virtual void SetMessage(eMessageType Type, const char *Text);
|
||||
virtual void Flush(void);
|
||||
};
|
||||
|
||||
#endif //__DISPLAYMESSAGE_H
|
131
displayreplay.c
Normal file
@ -0,0 +1,131 @@
|
||||
#define __STL_CONFIG_H
|
||||
#include "displayreplay.h"
|
||||
|
||||
cSDDisplayReplay::cSDDisplayReplay(cTemplate *replayTemplate, bool ModeOnly) {
|
||||
doOutput = true;
|
||||
initial = true;
|
||||
modeOnly = ModeOnly;
|
||||
numMarksLast = 0;
|
||||
lastMarks = NULL;
|
||||
if (!replayTemplate) {
|
||||
doOutput = false;
|
||||
esyslog("skindesigner: displayReplay no valid template - aborting");
|
||||
return;
|
||||
}
|
||||
replayView = new cDisplayReplayView(replayTemplate->GetRootView());
|
||||
if (!replayView->createOsd()) {
|
||||
doOutput = false;
|
||||
return;
|
||||
}
|
||||
replayView->DrawBackground(modeOnly);
|
||||
}
|
||||
|
||||
cSDDisplayReplay::~cSDDisplayReplay() {
|
||||
if (!doOutput)
|
||||
return;
|
||||
delete replayView;
|
||||
if (lastMarks) {
|
||||
delete[] lastMarks;
|
||||
}
|
||||
}
|
||||
|
||||
void cSDDisplayReplay::SetRecording(const cRecording *Recording) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
replayView->DrawTitle(Recording);
|
||||
replayView->DrawRecordingInformation(Recording);
|
||||
replayView->DrawScraperContent(Recording);
|
||||
}
|
||||
|
||||
void cSDDisplayReplay::SetMode(bool Play, bool Forward, int Speed) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
replayView->DrawControlIcons(Play, Forward, Speed, modeOnly);
|
||||
}
|
||||
|
||||
void cSDDisplayReplay::SetProgress(int Current, int Total) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
replayView->DrawProgressBar(Current, Total);
|
||||
if (MarksChanged()) {
|
||||
replayView->DrawMarks(marks, Total);
|
||||
}
|
||||
}
|
||||
|
||||
void cSDDisplayReplay::SetCurrent(const char *Current) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
replayView->DrawCurrent(Current);
|
||||
}
|
||||
|
||||
void cSDDisplayReplay::SetTotal(const char *Total) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
replayView->DrawTotal(Total);
|
||||
}
|
||||
|
||||
void cSDDisplayReplay::SetJump(const char *Jump) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
replayView->DrawJump(Jump);
|
||||
}
|
||||
|
||||
void cSDDisplayReplay::SetMessage(eMessageType Type, const char *Text) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
replayView->DrawMessage(Type, Text);
|
||||
}
|
||||
|
||||
void cSDDisplayReplay::Flush(void) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
replayView->DrawDate(modeOnly);
|
||||
if (initial) {
|
||||
replayView->DoFadeIn();
|
||||
initial = false;
|
||||
} else {
|
||||
replayView->Flush();
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Private Functions
|
||||
*****************************************************************************************/
|
||||
|
||||
bool cSDDisplayReplay::MarksChanged(void) {
|
||||
if (!marks)
|
||||
return false;
|
||||
int numMarks = marks->Count();
|
||||
if (numMarks != numMarksLast) {
|
||||
RememberMarks();
|
||||
return true;
|
||||
}
|
||||
if (!lastMarks)
|
||||
return false;
|
||||
int i=0;
|
||||
for (const cMark *m = marks->First(); m; m = marks->Next(m)) {
|
||||
if (m->Position() != lastMarks[i]) {
|
||||
RememberMarks();
|
||||
return true;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cSDDisplayReplay::RememberMarks(void) {
|
||||
if (!marks)
|
||||
return;
|
||||
numMarksLast = marks->Count();
|
||||
if (numMarksLast < 1)
|
||||
return;
|
||||
if (lastMarks) {
|
||||
delete[] lastMarks;
|
||||
}
|
||||
lastMarks = new int[numMarksLast];
|
||||
int i=0;
|
||||
for (const cMark *m = marks->First(); m; m = marks->Next(m)) {
|
||||
lastMarks[i] = m->Position();
|
||||
i++;
|
||||
}
|
||||
}
|
34
displayreplay.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef __DISPLAYREPLAY_H
|
||||
#define __DISPLAYREPLAY_H
|
||||
|
||||
#include <vdr/skins.h>
|
||||
#include <vdr/thread.h>
|
||||
#include "config.h"
|
||||
#include "libtemplate/template.h"
|
||||
#include "views/displayreplayview.h"
|
||||
|
||||
class cSDDisplayReplay : public cSkinDisplayReplay {
|
||||
private:
|
||||
cDisplayReplayView *replayView;
|
||||
bool initial;
|
||||
bool doOutput;
|
||||
bool modeOnly;
|
||||
int numMarksLast;
|
||||
int *lastMarks;
|
||||
bool MarksChanged(void);
|
||||
void RememberMarks(void);
|
||||
public:
|
||||
cSDDisplayReplay(cTemplate *replayTemplate, bool ModeOnly);
|
||||
virtual ~cSDDisplayReplay();
|
||||
virtual void SetRecording(const cRecording *Recording);
|
||||
virtual void SetTitle(const char *Title) {};
|
||||
virtual void SetMode(bool Play, bool Forward, int Speed);
|
||||
virtual void SetProgress(int Current, int Total);
|
||||
virtual void SetCurrent(const char *Current);
|
||||
virtual void SetTotal(const char *Total);
|
||||
virtual void SetJump(const char *Jump);
|
||||
virtual void SetMessage(eMessageType Type, const char *Text);
|
||||
virtual void Flush(void);
|
||||
};
|
||||
|
||||
#endif //__DISPLAYREPLAY_H
|
58
displaytracks.c
Normal file
@ -0,0 +1,58 @@
|
||||
#include "displaytracks.h"
|
||||
|
||||
|
||||
cSDDisplayTracks::cSDDisplayTracks(cTemplate *audiotracksTemplate, const char *Title, int NumTracks, const char * const *Tracks) {
|
||||
initial = true;
|
||||
numTracks = NumTracks;
|
||||
doOutput = true;
|
||||
currentTrack = 0;
|
||||
menuTitle = Title;
|
||||
if (!audiotracksTemplate) {
|
||||
esyslog("skindesigner: displayTracks no valid template - aborting");
|
||||
doOutput = false;
|
||||
return;
|
||||
}
|
||||
tracksView = new cDisplayAudiotracksView(NumTracks, audiotracksTemplate->GetRootView());
|
||||
if (!tracksView->createOsd()) {
|
||||
doOutput = false;
|
||||
return;
|
||||
}
|
||||
tracksView->DrawBackground();
|
||||
|
||||
cDisplayMenuListView *list = tracksView->GetListView();
|
||||
if (list) {
|
||||
for (int i = 0; i < NumTracks; i++) {
|
||||
list->AddTracksMenuItem(i, Tracks[i], (i==currentTrack)?true:false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cSDDisplayTracks::~cSDDisplayTracks() {
|
||||
if (!doOutput)
|
||||
return;
|
||||
delete tracksView;
|
||||
}
|
||||
|
||||
void cSDDisplayTracks::SetTrack(int Index, const char * const *Tracks) {
|
||||
cDisplayMenuListView *list = tracksView->GetListView();
|
||||
if (list) {
|
||||
list->AddTracksMenuItem(currentTrack, Tracks[currentTrack], false, true);
|
||||
list->AddTracksMenuItem(Index, Tracks[Index], true, true);
|
||||
currentTrack = Index;
|
||||
}
|
||||
}
|
||||
|
||||
void cSDDisplayTracks::SetAudioChannel(int AudioChannel) {
|
||||
tracksView->DrawHeader(menuTitle, AudioChannel);
|
||||
}
|
||||
|
||||
void cSDDisplayTracks::Flush(void) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
if (initial) {
|
||||
tracksView->DoFadeIn();
|
||||
}
|
||||
initial = false;
|
||||
tracksView->RenderMenuItems();
|
||||
tracksView->Flush();
|
||||
}
|
27
displaytracks.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef __DISPLAYTRACKS_H
|
||||
#define __DISPLAYTRACKS_H
|
||||
|
||||
#include <vdr/skins.h>
|
||||
#include <vdr/thread.h>
|
||||
#include "config.h"
|
||||
#include "libtemplate/template.h"
|
||||
#include "views/displayaudiotracksview.h"
|
||||
|
||||
class cSDDisplayTracks : public cSkinDisplayTracks {
|
||||
private:
|
||||
cDisplayAudiotracksView *tracksView;
|
||||
bool initial;
|
||||
int numTracks;
|
||||
bool doOutput;
|
||||
int currentTrack;
|
||||
const char *menuTitle;
|
||||
public:
|
||||
cSDDisplayTracks(cTemplate *audiotracksTemplate, const char *Title, int NumTracks, const char * const *Tracks);
|
||||
virtual ~cSDDisplayTracks();
|
||||
virtual void SetTrack(int Index, const char * const *Tracks);
|
||||
virtual void SetAudioChannel(int AudioChannel);
|
||||
virtual void Flush(void);
|
||||
};
|
||||
|
||||
|
||||
#endif //__DISPLAYTRACKS_H
|
43
displayvolume.c
Normal file
@ -0,0 +1,43 @@
|
||||
#include "displayvolume.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "libcore/helpers.h"
|
||||
|
||||
cSDDisplayVolume::cSDDisplayVolume(cTemplate *volumeTemplate) {
|
||||
doOutput = true;
|
||||
initial = true;
|
||||
if (!volumeTemplate) {
|
||||
doOutput = false;
|
||||
esyslog("skindesigner: displayVolume no valid template - aborting");
|
||||
return;
|
||||
}
|
||||
volumeView = new cDisplayVolumeView(volumeTemplate->GetRootView());
|
||||
if (!volumeView->createOsd()) {
|
||||
doOutput = false;
|
||||
} else {
|
||||
volumeView->DrawBackground();
|
||||
}
|
||||
}
|
||||
|
||||
cSDDisplayVolume::~cSDDisplayVolume() {
|
||||
if (!doOutput)
|
||||
return;
|
||||
delete volumeView;
|
||||
}
|
||||
|
||||
void cSDDisplayVolume::SetVolume(int Current, int Total, bool Mute) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
volumeView->DrawVolume(Current, Total, Mute);
|
||||
}
|
||||
|
||||
void cSDDisplayVolume::Flush(void) {
|
||||
if (!doOutput)
|
||||
return;
|
||||
if (initial) {
|
||||
volumeView->DoFadeIn();
|
||||
initial = false;
|
||||
} else {
|
||||
volumeView->Flush();
|
||||
}
|
||||
}
|
21
displayvolume.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef __DISPLAYVOLUME_H
|
||||
#define __DISPLAYVOLUME_H
|
||||
|
||||
#include <vdr/skins.h>
|
||||
#include "config.h"
|
||||
#include "libtemplate/template.h"
|
||||
#include "views/displayvolumeview.h"
|
||||
|
||||
class cSDDisplayVolume : public cSkinDisplayVolume {
|
||||
private:
|
||||
cDisplayVolumeView *volumeView;
|
||||
bool doOutput;
|
||||
bool initial;
|
||||
public:
|
||||
cSDDisplayVolume(cTemplate *volumeTemplate);
|
||||
virtual ~cSDDisplayVolume();
|
||||
virtual void SetVolume(int Current, int Total, bool Mute);
|
||||
virtual void Flush(void);
|
||||
};
|
||||
|
||||
#endif //__DISPLAYVOLUME_H
|
201
fonts/VDROpenSans/Apache License.txt
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
BIN
fonts/VDROpenSans/VDROpenSans-Bold.ttf
Normal file
BIN
fonts/VDROpenSans/VDROpenSans-BoldItalic.ttf
Normal file
BIN
fonts/VDROpenSans/VDROpenSans-ExtraBold.ttf
Normal file
BIN
fonts/VDROpenSans/VDROpenSans-ExtraBoldItalic.ttf
Normal file
BIN
fonts/VDROpenSans/VDROpenSans-Italic.ttf
Normal file
BIN
fonts/VDROpenSans/VDROpenSans-Light.ttf
Normal file
BIN
fonts/VDROpenSans/VDROpenSans-LightItalic.ttf
Normal file
BIN
fonts/VDROpenSans/VDROpenSans-Regular.ttf
Normal file
BIN
fonts/VDROpenSans/VDROpenSans-Semibold.ttf
Normal file
BIN
fonts/VDROpenSans/VDROpenSans-SemiboldItalic.ttf
Normal file
174
libcore/fontmanager.c
Normal file
@ -0,0 +1,174 @@
|
||||
#include "fontmanager.h"
|
||||
#include "../config.h"
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
using namespace std;
|
||||
|
||||
cMutex cFontManager::mutex;
|
||||
|
||||
cFontManager::cFontManager() {
|
||||
}
|
||||
|
||||
cFontManager::~cFontManager() {
|
||||
DeleteFonts();
|
||||
}
|
||||
|
||||
void cFontManager::CacheFonts(cTemplate *tpl) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
|
||||
vector< pair<string, int> > usedFonts = tpl->GetUsedFonts();
|
||||
|
||||
cStringList availableFonts;
|
||||
cFont::GetAvailableFontNames(&availableFonts);
|
||||
|
||||
for (vector< pair<string, int> >::iterator ft = usedFonts.begin(); ft != usedFonts.end(); ft++) {
|
||||
string fontName = ft->first;
|
||||
int fontSize = ft->second;
|
||||
if (fontSize < 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int fontAvailable = availableFonts.Find(fontName.c_str());
|
||||
if (fontAvailable == -1) {
|
||||
esyslog("skindesigner: font %s not available, skipping", fontName.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
InsertFont(fontName, fontSize);
|
||||
}
|
||||
}
|
||||
|
||||
void cFontManager::Debug(void) {
|
||||
dsyslog("skindesigner: fontmanager fonts available:");
|
||||
for (map < string, map< int, cFont* > >::iterator fts = fonts.begin(); fts != fonts.end(); fts++) {
|
||||
dsyslog("skindesigner: FontName %s", fts->first.c_str());
|
||||
for (map<int, cFont*>::iterator ftSizes = (fts->second).begin(); ftSizes != (fts->second).end(); ftSizes++) {
|
||||
int confHeight = ftSizes->first;
|
||||
int realHeight = (ftSizes->second)->Height();
|
||||
dsyslog("skindesigner: fontSize %d, fontHeight %d, ratio %f", confHeight, realHeight, (double)confHeight / (double)realHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cFontManager::ListAvailableFonts(void) {
|
||||
cStringList availableFonts;
|
||||
cFont::GetAvailableFontNames(&availableFonts);
|
||||
int numFonts = availableFonts.Size();
|
||||
esyslog("skindesigner: %d Fonts available:", numFonts);
|
||||
for (int i=0; i<numFonts; i++) {
|
||||
esyslog("skindesigner: font %d: %s", i, availableFonts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void cFontManager::DeleteFonts() {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
for(map<string, map<int,cFont*> >::iterator it = fonts.begin(); it != fonts.end(); it++) {
|
||||
for(map<int,cFont*>::iterator it2 = (it->second).begin(); it2 != (it->second).end(); it2++) {
|
||||
delete it2->second;
|
||||
}
|
||||
}
|
||||
fonts.clear();
|
||||
}
|
||||
|
||||
int cFontManager::Width(string fontName, int fontSize, const char *text) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!text)
|
||||
return 0;
|
||||
cFont *font = GetFont(fontName, fontSize);
|
||||
//if not already cached, load it new
|
||||
if (!font)
|
||||
InsertFont(fontName, fontSize);
|
||||
font = GetFont(fontName, fontSize);
|
||||
if (!font)
|
||||
return 0;
|
||||
int width = font->Width(text);
|
||||
return width;
|
||||
}
|
||||
|
||||
int cFontManager::Height(string fontName, int fontSize) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
cFont *font = GetFont(fontName, fontSize);
|
||||
//if not already cached, load it new
|
||||
if (!font)
|
||||
InsertFont(fontName, fontSize);
|
||||
font = GetFont(fontName, fontSize);
|
||||
if (!font)
|
||||
return 0;
|
||||
return font->Height();
|
||||
}
|
||||
|
||||
cFont *cFontManager::Font(string fontName, int fontSize) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
cFont *font = GetFont(fontName, fontSize);
|
||||
//if not already cached, load it new
|
||||
if (!font)
|
||||
InsertFont(fontName, fontSize);
|
||||
font = GetFont(fontName, fontSize);
|
||||
return font;
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
* Private Functions
|
||||
********************************************************************************/
|
||||
|
||||
cFont *cFontManager::CreateFont(string name, int size) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
cFont *fontTmp = cFont::CreateFont(name.c_str(), size);
|
||||
if (!fontTmp)
|
||||
fontTmp = cFont::CreateFont(Setup.FontOsd, size);
|
||||
int realHeight = fontTmp->Height();
|
||||
delete fontTmp;
|
||||
cFont *font = cFont::CreateFont(name.c_str(), (double)size / (double)realHeight * (double)size);
|
||||
if (!font)
|
||||
font = cFont::CreateFont(Setup.FontOsd, (double)size / (double)realHeight * (double)size);
|
||||
return font;
|
||||
}
|
||||
|
||||
void cFontManager::InsertFont(string name, int size) {
|
||||
cFont *newFont = CreateFont(name, size);
|
||||
if (!newFont)
|
||||
return;
|
||||
map < string, map< int, cFont* > >::iterator hit = fonts.find(name);
|
||||
if (hit != fonts.end()) {
|
||||
(hit->second).insert(pair<int, cFont*>(size, newFont));
|
||||
} else {
|
||||
map<int, cFont*> fontsizes;
|
||||
fontsizes.insert(pair<int, cFont*>(size, newFont));
|
||||
fonts.insert(pair<string, map<int, cFont*> >(name, fontsizes));
|
||||
}
|
||||
}
|
||||
|
||||
cFont *cFontManager::GetFont(string name, int size) {
|
||||
map< string, map<int,cFont*> >::iterator hitName = fonts.find(name);
|
||||
if (hitName == fonts.end())
|
||||
return NULL;
|
||||
map<int,cFont*>::iterator hitSize = (hitName->second).find(size);
|
||||
if (hitSize == (hitName->second).end())
|
||||
return NULL;
|
||||
return hitSize->second;
|
||||
}
|
||||
|
||||
int cFontManager::GetFontHeight(const char *name, int height, int charWidth) {
|
||||
FT_Library library;
|
||||
FT_Face face;
|
||||
cString fontFileName = cFont::GetFontFileName(name);
|
||||
|
||||
int descender = 0;
|
||||
int y_ppem = 0;
|
||||
int error = FT_Init_FreeType(&library);
|
||||
if (error) return 0;
|
||||
error = FT_New_Face(library, fontFileName, 0, &face);
|
||||
if (error) return 0;
|
||||
error = FT_Set_Char_Size(face, charWidth * 64, height * 64, 0, 0);
|
||||
if (error) return 0;
|
||||
|
||||
descender = face->size->metrics.descender/64;
|
||||
y_ppem = face->size->metrics.y_ppem;
|
||||
int realHeight = y_ppem + descender;
|
||||
|
||||
FT_Done_Face(face);
|
||||
FT_Done_FreeType(library);
|
||||
|
||||
return realHeight;
|
||||
}
|
35
libcore/fontmanager.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef __FONTMANAGER_H
|
||||
#define __FONTMANAGER_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <vdr/skins.h>
|
||||
|
||||
#include "../libtemplate/template.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class cFontManager {
|
||||
private:
|
||||
static cMutex mutex;
|
||||
map < string, map< int, cFont* > > fonts;
|
||||
cFont *CreateFont(string name, int size);
|
||||
void InsertFont(string name, int size);
|
||||
cFont *GetFont(string name, int size);
|
||||
int GetFontHeight(const char *name, int height, int charWidth = 0);
|
||||
public:
|
||||
cFontManager();
|
||||
~cFontManager();
|
||||
void Lock(void) { mutex.Lock(); };
|
||||
void Unlock(void) { mutex.Unlock(); };
|
||||
void CacheFonts(cTemplate *tpl);
|
||||
void DeleteFonts(void);
|
||||
int Width(string fontName, int fontSize, const char *text);
|
||||
int Height(string fontName, int fontSize);
|
||||
cFont *Font(string fontName, int fontSize);
|
||||
void Debug(void);
|
||||
void ListAvailableFonts(void);
|
||||
};
|
||||
|
||||
#endif //__FONTMANAGER_H
|
155
libcore/helpers.c
Normal file
@ -0,0 +1,155 @@
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include "helpers.h"
|
||||
#include <vdr/skins.h>
|
||||
|
||||
cPlugin *GetScraperPlugin(void) {
|
||||
static cPlugin *pScraper = cPluginManager::GetPlugin("scraper2vdr");
|
||||
if( !pScraper ) // if it doesn't exit, try tvscraper
|
||||
pScraper = cPluginManager::GetPlugin("tvscraper");
|
||||
return pScraper;
|
||||
}
|
||||
|
||||
cSize ScaleToFit(int widthMax, int heightMax, int widthOriginal, int heightOriginal) {
|
||||
int width = 1;
|
||||
int height = 1;
|
||||
|
||||
if ((widthMax == 0)||(heightMax==0)||(widthOriginal==0)||(heightOriginal==0))
|
||||
return cSize(width, height);
|
||||
|
||||
if ((widthOriginal <= widthMax) && (heightOriginal <= heightMax)) {
|
||||
width = widthOriginal;
|
||||
height = heightOriginal;
|
||||
} else if ((widthOriginal > widthMax) && (heightOriginal <= heightMax)) {
|
||||
width = widthMax;
|
||||
height = (double)width/(double)widthOriginal * heightOriginal;
|
||||
} else if ((widthOriginal <= widthMax) && (heightOriginal > heightMax)) {
|
||||
height = heightMax;
|
||||
width = (double)height/(double)heightOriginal * widthOriginal;
|
||||
} else {
|
||||
width = widthMax;
|
||||
height = (double)width/(double)widthOriginal * heightOriginal;
|
||||
if (height > heightMax) {
|
||||
height = heightMax;
|
||||
width = (double)height/(double)heightOriginal * widthOriginal;
|
||||
}
|
||||
}
|
||||
return cSize(width, height);
|
||||
}
|
||||
|
||||
int Minimum(int a, int b, int c, int d, int e, int f) {
|
||||
int min = a;
|
||||
if (b < min) min = b;
|
||||
if (c < min) min = c;
|
||||
if (d < min) min = d;
|
||||
if (e < min) min = e;
|
||||
if (f < min) min = f;
|
||||
return min;
|
||||
}
|
||||
|
||||
string CutText(string &text, int width, string fontName, int fontSize) {
|
||||
if (width <= fontManager->Font(fontName, fontSize)->Size())
|
||||
return text.c_str();
|
||||
cTextWrapper twText;
|
||||
twText.Set(text.c_str(), fontManager->Font(fontName, fontSize), width);
|
||||
string cuttedTextNative = twText.GetLine(0);
|
||||
stringstream sstrText;
|
||||
sstrText << cuttedTextNative << "...";
|
||||
string cuttedText = sstrText.str();
|
||||
int actWidth = fontManager->Width(fontName, fontSize, cuttedText.c_str());
|
||||
if (actWidth > width) {
|
||||
int overlap = actWidth - width;
|
||||
int charWidth = fontManager->Width(fontName, fontSize, ".");
|
||||
if (charWidth == 0)
|
||||
charWidth = 1;
|
||||
int cutChars = overlap / charWidth;
|
||||
if (cutChars > 0) {
|
||||
cuttedTextNative = cuttedTextNative.substr(0, cuttedTextNative.length() - cutChars);
|
||||
stringstream sstrText2;
|
||||
sstrText2 << cuttedTextNative << "...";
|
||||
cuttedText = sstrText2.str();
|
||||
}
|
||||
}
|
||||
return cuttedText;
|
||||
}
|
||||
|
||||
|
||||
string StrToLowerCase(string str) {
|
||||
string lowerCase = str;
|
||||
const int length = lowerCase.length();
|
||||
for(int i=0; i < length; ++i) {
|
||||
lowerCase[i] = std::tolower(lowerCase[i]);
|
||||
}
|
||||
return lowerCase;
|
||||
}
|
||||
|
||||
bool isNumber(const string& s) {
|
||||
string::const_iterator it = s.begin();
|
||||
while (it != s.end() && std::isdigit(*it)) ++it;
|
||||
return !s.empty() && it == s.end();
|
||||
}
|
||||
|
||||
bool FileExists(const string &path, const string &name, const string &ext) {
|
||||
stringstream fileName;
|
||||
fileName << path << name << "." << ext;
|
||||
struct stat buffer;
|
||||
return (stat (fileName.str().c_str(), &buffer) == 0);
|
||||
}
|
||||
|
||||
bool FirstFileInFolder(string &path, string &extension, string &fileName) {
|
||||
DIR *folder = NULL;
|
||||
struct dirent *file;
|
||||
folder = opendir(path.c_str());
|
||||
if (!folder)
|
||||
return false;
|
||||
while (file = readdir(folder)) {
|
||||
if (endswith(file->d_name, extension.c_str())) {
|
||||
string currentFileName = file->d_name;
|
||||
int strlength = currentFileName.size();
|
||||
if (strlength < 8)
|
||||
continue;
|
||||
fileName = currentFileName;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// split: receives a char delimiter; returns a vector of strings
|
||||
// By default ignores repeated delimiters, unless argument rep == 1.
|
||||
vector<string>& splitstring::split(char delim, int rep) {
|
||||
if (!flds.empty()) flds.clear(); // empty vector if necessary
|
||||
string work = data();
|
||||
string buf = "";
|
||||
int i = 0;
|
||||
while (i < work.length()) {
|
||||
if (work[i] != delim)
|
||||
buf += work[i];
|
||||
else if (rep == 1) {
|
||||
flds.push_back(buf);
|
||||
buf = "";
|
||||
} else if (buf.length() > 0) {
|
||||
flds.push_back(buf);
|
||||
buf = "";
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (!buf.empty())
|
||||
flds.push_back(buf);
|
||||
return flds;
|
||||
}
|
||||
|
||||
cStopWatch::cStopWatch(void) {
|
||||
start = cTimeMs::Now();
|
||||
last = start;
|
||||
}
|
||||
|
||||
void cStopWatch::Report(const char* message) {
|
||||
dsyslog("skindesigner: %s - needed %d ms", message, (int)(cTimeMs::Now() - last));
|
||||
last = cTimeMs::Now();
|
||||
}
|
||||
|
||||
void cStopWatch::Stop(const char* message) {
|
||||
dsyslog("skindesigner: %s - needed %d ms", message, (int)(cTimeMs::Now() - start));
|
||||
}
|
35
libcore/helpers.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef __HELPERS_H
|
||||
#define __HELPERS_H
|
||||
|
||||
#include <vdr/osd.h>
|
||||
#include <vdr/plugin.h>
|
||||
#include "../config.h"
|
||||
|
||||
cPlugin *GetScraperPlugin(void);
|
||||
|
||||
cSize ScaleToFit(int widthMax, int heightMax, int widthOriginal, int heightOriginal);
|
||||
int Minimum(int a, int b, int c, int d, int e, int f);
|
||||
std::string CutText(string &text, int width, string fontName, int fontSize);
|
||||
std::string StrToLowerCase(string str);
|
||||
bool isNumber(const string& s);
|
||||
bool FileExists(const string &path, const string &name, const string &ext);
|
||||
bool FirstFileInFolder(string &path, string &extension, string &fileName);
|
||||
|
||||
class splitstring : public std::string {
|
||||
std::vector<std::string> flds;
|
||||
public:
|
||||
splitstring(const char *s) : std::string(s) { };
|
||||
std::vector<std::string>& split(char delim, int rep=0);
|
||||
};
|
||||
|
||||
class cStopWatch {
|
||||
private:
|
||||
uint64_t start;
|
||||
uint64_t last;
|
||||
public:
|
||||
cStopWatch(void);
|
||||
~cStopWatch(void) {};
|
||||
void Report(const char* message);
|
||||
void Stop(const char* message);
|
||||
};
|
||||
#endif // __HELPERS_H
|
389
libcore/imagecache.c
Normal file
@ -0,0 +1,389 @@
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <sys/stat.h>
|
||||
#include "imagecache.h"
|
||||
#include "../config.h"
|
||||
#include "helpers.h"
|
||||
|
||||
using namespace Magick;
|
||||
|
||||
cMutex cImageCache::mutex;
|
||||
|
||||
string cImageCache::items[16] = { "Schedule", "Channels", "Timers", "Recordings", "Setup", "Commands",
|
||||
"OSD", "EPG", "DVB", "LNB", "CAM", "Recording", "Replay", "Miscellaneous", "Plugins", "Restart"};
|
||||
|
||||
cImageCache::cImageCache() : cImageMagickWrapper() {
|
||||
tempStaticLogo = NULL;
|
||||
}
|
||||
|
||||
cImageCache::~cImageCache() {
|
||||
Clear();
|
||||
if (tempStaticLogo) {
|
||||
delete tempStaticLogo;
|
||||
tempStaticLogo = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void cImageCache::CacheLogo(int width, int height) {
|
||||
if (config.numLogosPerSizeInitial == 0)
|
||||
return;
|
||||
if (width == 0 || height == 0)
|
||||
return;
|
||||
|
||||
int channelsCached = 0;
|
||||
|
||||
for (const cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) {
|
||||
if (channelsCached >= config.numLogosPerSizeInitial)
|
||||
break;
|
||||
if (channel->GroupSep()) {
|
||||
continue;
|
||||
}
|
||||
bool success = LoadLogo(channel);
|
||||
if (success) {
|
||||
channelsCached++;
|
||||
cImage *image = CreateImage(width, height);
|
||||
stringstream logoName;
|
||||
logoName << *channel->GetChannelID().ToString() << "_" << width << "x" << height;
|
||||
std::map<std::string, cImage*>::iterator hit = channelLogoCache.find(logoName.str());
|
||||
if (hit != channelLogoCache.end()) {
|
||||
delete image;
|
||||
return;
|
||||
}
|
||||
channelLogoCache.insert(pair<string, cImage*>(logoName.str(), image));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cImage *cImageCache::GetLogo(string channelID, int width, int height) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
|
||||
stringstream logoName;
|
||||
logoName << channelID << "_" << width << "x" << height;
|
||||
|
||||
std::map<std::string, cImage*>::iterator hit = channelLogoCache.find(logoName.str());
|
||||
|
||||
if (hit != channelLogoCache.end()) {
|
||||
return (cImage*)hit->second;
|
||||
} else {
|
||||
tChannelID chanID = tChannelID::FromString(channelID.c_str());
|
||||
const cChannel *channel = Channels.GetByChannelID(chanID);
|
||||
if (!channel)
|
||||
return NULL;
|
||||
bool success = LoadLogo(channel);
|
||||
if (success) {
|
||||
if (config.limitLogoCache && (channelLogoCache.size() >= config.numLogosMax)) {
|
||||
//logo cache is full, don't cache anymore
|
||||
if (tempStaticLogo) {
|
||||
delete tempStaticLogo;
|
||||
tempStaticLogo = NULL;
|
||||
}
|
||||
tempStaticLogo = CreateImage(width, height);
|
||||
return tempStaticLogo;
|
||||
} else {
|
||||
//add requested logo to cache
|
||||
cImage *image = CreateImage(width, height);
|
||||
channelLogoCache.insert(pair<string, cImage*>(logoName.str(), image));
|
||||
hit = channelLogoCache.find(logoName.str());
|
||||
if (hit != channelLogoCache.end()) {
|
||||
return (cImage*)hit->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cImage *cImageCache::GetSeparatorLogo(string name, int width, int height) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
|
||||
stringstream logoName;
|
||||
logoName << name << "_" << width << "x" << height;
|
||||
|
||||
std::map<std::string, cImage*>::iterator hit = channelLogoCache.find(logoName.str());
|
||||
|
||||
if (hit != channelLogoCache.end()) {
|
||||
return (cImage*)hit->second;
|
||||
} else {
|
||||
bool success = LoadSeparatorLogo(name);
|
||||
if (success) {
|
||||
//add requested logo to cache
|
||||
cImage *image = CreateImage(width, height);
|
||||
channelLogoCache.insert(pair<string, cImage*>(logoName.str(), image));
|
||||
hit = channelLogoCache.find(logoName.str());
|
||||
if (hit != channelLogoCache.end()) {
|
||||
return (cImage*)hit->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool cImageCache::LogoExists(string channelID) {
|
||||
tChannelID chanID = tChannelID::FromString(channelID.c_str());
|
||||
const cChannel *channel = Channels.GetByChannelID(chanID);
|
||||
if (!channel)
|
||||
return false;
|
||||
string logoPath = *cString::sprintf("%s%s/logos/", *config.skinPath, Setup.OSDTheme);
|
||||
string logoLower = StrToLowerCase(channel->Name());
|
||||
string logoExt = *config.logoExtension;
|
||||
bool logoExists = FileExists(logoPath, logoLower, logoExt);
|
||||
if (logoExists) {
|
||||
return true;
|
||||
}
|
||||
logoExists = FileExists(logoPath, channelID, logoExt);
|
||||
if (logoExists) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cImageCache::SeparatorLogoExists(string name) {
|
||||
string separatorPath = *cString::sprintf("%s%s/logos/separatorlogos/", *config.skinPath, Setup.OSDTheme);
|
||||
string nameLower = StrToLowerCase(name.c_str());
|
||||
string logoExt = *config.logoExtension;
|
||||
bool logoExists = FileExists(separatorPath, nameLower, logoExt);
|
||||
if (logoExists) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cImageCache::CacheIcon(eImageType type, string name, int width, int height) {
|
||||
if (width < 1 || width > 1920 || height < 1 || height > 1080)
|
||||
return;
|
||||
bool success = LoadIcon(type, name);
|
||||
if (!success)
|
||||
return;
|
||||
stringstream iconName;
|
||||
iconName << name << "_" << width << "x" << height;
|
||||
cImage *image = CreateImage(width, height, true);
|
||||
iconCache.insert(pair<string, cImage*>(iconName.str(), image));
|
||||
}
|
||||
|
||||
cImage *cImageCache::GetIcon(eImageType type, string name, int width, int height) {
|
||||
if (width < 1 || width > 1920 || height < 1 || height > 1080)
|
||||
return NULL;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
stringstream iconName;
|
||||
iconName << name << "_" << width << "x" << height;
|
||||
map<string, cImage*>::iterator hit = iconCache.find(iconName.str());
|
||||
if (hit != iconCache.end()) {
|
||||
return (cImage*)hit->second;
|
||||
} else {
|
||||
bool success = LoadIcon(type, name);
|
||||
if (!success)
|
||||
return NULL;
|
||||
cImage *image = CreateImage(width, height, true);
|
||||
iconCache.insert(pair<string, cImage*>(iconName.str(), image));
|
||||
hit = iconCache.find(iconName.str());
|
||||
if (hit != iconCache.end()) {
|
||||
return (cImage*)hit->second;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
string cImageCache::GetIconName(string label) {
|
||||
//check for standard menu entries
|
||||
for (int i=0; i<16; i++) {
|
||||
string s = trVDR(items[i].c_str());
|
||||
if (s == label) {
|
||||
return *cString::sprintf("standardicons/%s", items[i].c_str());
|
||||
}
|
||||
}
|
||||
//check for special main menu entries "stop recording", "stop replay"
|
||||
string stopRecording = skipspace(trVDR(" Stop recording "));
|
||||
string stopReplay = skipspace(trVDR(" Stop replaying"));
|
||||
try {
|
||||
if (label.substr(0, stopRecording.size()) == stopRecording) {
|
||||
return "standardicons/StopRecording";
|
||||
}
|
||||
if (label.substr(0, stopReplay.size()) == stopReplay) {
|
||||
return "standardicons/StopReplay";
|
||||
}
|
||||
} catch (...) {}
|
||||
//check for Plugins
|
||||
for (int i = 0; ; i++) {
|
||||
cPlugin *p = cPluginManager::GetPlugin(i);
|
||||
if (p) {
|
||||
const char *mainMenuEntry = p->MainMenuEntry();
|
||||
if (mainMenuEntry) {
|
||||
string plugMainEntry = mainMenuEntry;
|
||||
try {
|
||||
if (label.substr(0, plugMainEntry.size()) == plugMainEntry) {
|
||||
return *cString::sprintf("pluginicons/%s", p->Name());
|
||||
}
|
||||
} catch (...) {}
|
||||
}
|
||||
} else
|
||||
break;
|
||||
}
|
||||
return *cString::sprintf("customicons/%s", label.c_str());
|
||||
}
|
||||
|
||||
void cImageCache::CacheSkinpart(string name, int width, int height) {
|
||||
if (width < 1 || width > 1920 || height < 1 || height > 1080)
|
||||
return;
|
||||
bool success = LoadSkinpart(name);
|
||||
if (!success)
|
||||
return;
|
||||
stringstream iconName;
|
||||
iconName << name << "_" << width << "x" << height;
|
||||
cImage *image = CreateImage(width, height, false);
|
||||
skinPartsCache.insert(pair<string, cImage*>(iconName.str(), image));
|
||||
}
|
||||
|
||||
cImage *cImageCache::GetSkinpart(string name, int width, int height) {
|
||||
if (width < 1 || width > 1920 || height < 1 || height > 1080)
|
||||
return NULL;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
stringstream iconName;
|
||||
iconName << name << "_" << width << "x" << height;
|
||||
map<string, cImage*>::iterator hit = skinPartsCache.find(iconName.str());
|
||||
if (hit != skinPartsCache.end()) {
|
||||
return (cImage*)hit->second;
|
||||
} else {
|
||||
bool success = LoadSkinpart(name);
|
||||
if (!success)
|
||||
return NULL;
|
||||
cImage *image = CreateImage(width, height, false);
|
||||
skinPartsCache.insert(pair<string, cImage*>(iconName.str(), image));
|
||||
hit = skinPartsCache.find(iconName.str());
|
||||
if (hit != skinPartsCache.end()) {
|
||||
return (cImage*)hit->second;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool cImageCache::LoadIcon(eImageType type, string name) {
|
||||
bool success = false;
|
||||
cString subdir("");
|
||||
if (type == itMenuIcon)
|
||||
subdir = "menuicons";
|
||||
else if (type == itIcon)
|
||||
subdir = "icons";
|
||||
cString iconPath = cString::sprintf("%s%s/graphics/%s/", *config.skinPath, Setup.OSDTheme, *subdir);
|
||||
success = LoadImage(name, *iconPath, "png");
|
||||
if (success) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cImageCache::LoadLogo(const cChannel *channel) {
|
||||
if (!channel)
|
||||
return false;
|
||||
cString logoPath = cString::sprintf("%s%s/logos/", *config.skinPath, Setup.OSDTheme);
|
||||
string channelID = StrToLowerCase(*(channel->GetChannelID().ToString()));
|
||||
string logoLower = StrToLowerCase(channel->Name());
|
||||
bool success = false;
|
||||
success = LoadImage(channelID.c_str(), *logoPath, *config.logoExtension);
|
||||
if (success)
|
||||
return true;
|
||||
success = LoadImage(logoLower.c_str(), *logoPath, *config.logoExtension);
|
||||
if (success)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cImageCache::LoadSeparatorLogo(string name) {
|
||||
cString separatorPath = cString::sprintf("%s%s/logos/separatorlogos/", *config.skinPath, Setup.OSDTheme);
|
||||
string nameLower = StrToLowerCase(name.c_str());
|
||||
bool success = false;
|
||||
success = LoadImage(nameLower.c_str(), *separatorPath, *config.logoExtension);
|
||||
if (success)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cImageCache::LoadSkinpart(string name) {
|
||||
bool success = false;
|
||||
cString iconPath = cString::sprintf("%s%s/graphics/skinparts/", *config.skinPath, Setup.OSDTheme);
|
||||
success = LoadImage(name, *iconPath, "png");
|
||||
if (success) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cImageCache::Clear(void) {
|
||||
for(map<string, cImage*>::const_iterator it = iconCache.begin(); it != iconCache.end(); it++) {
|
||||
cImage *img = (cImage*)it->second;
|
||||
delete img;
|
||||
}
|
||||
iconCache.clear();
|
||||
|
||||
for(map<string, cImage*>::const_iterator it = channelLogoCache.begin(); it != channelLogoCache.end(); it++) {
|
||||
cImage *img = (cImage*)it->second;
|
||||
delete img;
|
||||
}
|
||||
channelLogoCache.clear();
|
||||
|
||||
for(map<std::string, cImage*>::const_iterator it = skinPartsCache.begin(); it != skinPartsCache.end(); it++) {
|
||||
cImage *img = (cImage*)it->second;
|
||||
delete img;
|
||||
}
|
||||
skinPartsCache.clear();
|
||||
}
|
||||
|
||||
void cImageCache::Debug(bool full) {
|
||||
int sizeIconCache = 0;
|
||||
int numIcons = 0;
|
||||
GetIconCacheSize(numIcons, sizeIconCache);
|
||||
dsyslog("skindesigner: cached %d icons - size %d byte", numIcons, sizeIconCache);
|
||||
if (full) {
|
||||
for(std::map<std::string, cImage*>::const_iterator it = iconCache.begin(); it != iconCache.end(); it++) {
|
||||
string name = it->first;
|
||||
dsyslog("skindesigner: cached icon %s", name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
int sizeLogoCache = 0;
|
||||
int numLogos = 0;
|
||||
GetLogoCacheSize(numLogos, sizeLogoCache);
|
||||
dsyslog("skindesigner: cached %d logos - size %d byte", numLogos, sizeLogoCache);
|
||||
if (full) {
|
||||
for(std::map<std::string, cImage*>::const_iterator it = channelLogoCache.begin(); it != channelLogoCache.end(); it++) {
|
||||
string name = it->first;
|
||||
dsyslog("skindesigner: cached logo %s", name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
int sizeSkinpartCache = 0;
|
||||
int numSkinparts = 0;
|
||||
GetSkinpartsCacheSize(numSkinparts, sizeSkinpartCache);
|
||||
dsyslog("skindesigner: cached %d skinparts - size %d byte", numSkinparts, sizeSkinpartCache);
|
||||
if (full) {
|
||||
for(std::map<std::string, cImage*>::const_iterator it = skinPartsCache.begin(); it != skinPartsCache.end(); it++) {
|
||||
string name = it->first;
|
||||
dsyslog("skindesigner: cached skinpart %s", name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cImageCache::GetIconCacheSize(int &num, int &size) {
|
||||
num = iconCache.size();
|
||||
for (map<string, cImage*>::iterator icon = iconCache.begin(); icon != iconCache.end(); icon++) {
|
||||
cImage* img = icon->second;
|
||||
size += img->Width() * img->Height() * sizeof(tColor);
|
||||
}
|
||||
}
|
||||
|
||||
void cImageCache::GetLogoCacheSize(int &num, int &size) {
|
||||
num = channelLogoCache.size();
|
||||
for (map<string, cImage*>::iterator logo = channelLogoCache.begin(); logo != channelLogoCache.end(); logo++) {
|
||||
cImage* img = logo->second;
|
||||
size += img->Width() * img->Height() * sizeof(tColor);
|
||||
}
|
||||
}
|
||||
|
||||
void cImageCache::GetSkinpartsCacheSize(int &num, int &size) {
|
||||
num = skinPartsCache.size();
|
||||
for (map<string, cImage*>::iterator skinpart = skinPartsCache.begin(); skinpart != skinPartsCache.end(); skinpart++) {
|
||||
cImage* img = skinpart->second;
|
||||
size += img->Width() * img->Height() * sizeof(tColor);
|
||||
}
|
||||
}
|
53
libcore/imagecache.h
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef __NOPACITY_IMAGECACHE_H
|
||||
#define __NOPACITY_IMAGECACHE_H
|
||||
|
||||
#define X_DISPLAY_MISSING
|
||||
|
||||
#include <vdr/osd.h>
|
||||
#include <vdr/skins.h>
|
||||
#include <Magick++.h>
|
||||
#include <vector>
|
||||
#include "imagemagickwrapper.h"
|
||||
#include "../libtemplate/templatefunction.h"
|
||||
|
||||
using namespace Magick;
|
||||
|
||||
class cImageCache : public cImageMagickWrapper {
|
||||
public:
|
||||
cImageCache();
|
||||
~cImageCache();
|
||||
void Lock(void) { mutex.Lock(); }
|
||||
void Unlock(void) { mutex.Unlock(); }
|
||||
//channel logos
|
||||
void CacheLogo(int width, int height);
|
||||
cImage *GetLogo(string channelID, int width, int height);
|
||||
bool LogoExists(string channelID);
|
||||
cImage *GetSeparatorLogo(string name, int width, int height);
|
||||
bool SeparatorLogoExists(string name);
|
||||
//icons
|
||||
void CacheIcon(eImageType type, string path, int width, int height);
|
||||
cImage *GetIcon(eImageType type, string name, int width, int height);
|
||||
string GetIconName(string label);
|
||||
//skinparts
|
||||
void CacheSkinpart(string path, int width, int height);
|
||||
cImage *GetSkinpart(string name, int width, int height);
|
||||
//helpers
|
||||
void Clear(void);
|
||||
void Debug(bool full);
|
||||
void GetIconCacheSize(int &num, int &size);
|
||||
void GetLogoCacheSize(int &num, int &size);
|
||||
void GetSkinpartsCacheSize(int &num, int &size);
|
||||
private:
|
||||
static cMutex mutex;
|
||||
static string items[16];
|
||||
cImage *tempStaticLogo;
|
||||
map<string, cImage*> iconCache;
|
||||
map<string, cImage*> channelLogoCache;
|
||||
map<string, cImage*> skinPartsCache;
|
||||
bool LoadIcon(eImageType type, string name);
|
||||
bool LoadLogo(const cChannel *channel);
|
||||
bool LoadSeparatorLogo(string name);
|
||||
bool LoadSkinpart(string name);
|
||||
};
|
||||
|
||||
#endif //__NOPACITY_IMAGECACHE_H
|
56
libcore/imageloader.c
Normal file
@ -0,0 +1,56 @@
|
||||
#include "../config.h"
|
||||
#include "helpers.h"
|
||||
#include "imageloader.h"
|
||||
#include <math.h>
|
||||
#include <string>
|
||||
#include <dirent.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace Magick;
|
||||
|
||||
cImageLoader::cImageLoader() : cImageMagickWrapper() {
|
||||
}
|
||||
|
||||
cImageLoader::~cImageLoader() {
|
||||
}
|
||||
|
||||
cImage cImageLoader::GetImage() {
|
||||
return CreateImageCopy();
|
||||
}
|
||||
|
||||
bool cImageLoader::LoadImage(const char *path, int width, int height) {
|
||||
if (cImageMagickWrapper::LoadImage(path)) {
|
||||
buffer.sample(Geometry(width, height));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cImageLoader::DeterminateChannelLogoSize(int &width, int &height) {
|
||||
cString logoPath = cString::sprintf("%s%s/logos/", *config.skinPath, Setup.OSDTheme);
|
||||
cString logoExt = config.logoExtension;
|
||||
DIR *folder = NULL;
|
||||
struct dirent *file;
|
||||
folder = opendir(logoPath);
|
||||
if (!folder) {
|
||||
return;
|
||||
}
|
||||
while (file = readdir(folder)) {
|
||||
if (endswith(file->d_name, *logoExt)) {
|
||||
std::stringstream filePath;
|
||||
filePath << *logoPath << file->d_name;
|
||||
Image logo;
|
||||
try {
|
||||
logo.read(filePath.str().c_str());
|
||||
Geometry g = logo.size();
|
||||
int logoWidth = g.width();
|
||||
int logoHeight = g.height();
|
||||
if (logoWidth > 0 && logoHeight > 0) {
|
||||
width = logoWidth;
|
||||
height = logoHeight;
|
||||
return;
|
||||
}
|
||||
} catch( ... ) { }
|
||||
}
|
||||
}
|
||||
}
|
23
libcore/imageloader.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef __NOPACITY_IMAGELOADER_H
|
||||
#define __NOPACITY_IMAGELOADER_H
|
||||
|
||||
#define X_DISPLAY_MISSING
|
||||
|
||||
#include <vdr/osd.h>
|
||||
#include <vdr/skins.h>
|
||||
#include <Magick++.h>
|
||||
#include "imagemagickwrapper.h"
|
||||
|
||||
using namespace Magick;
|
||||
|
||||
class cImageLoader : public cImageMagickWrapper {
|
||||
public:
|
||||
cImageLoader();
|
||||
~cImageLoader();
|
||||
cImage GetImage();
|
||||
bool LoadImage(const char *path, int width, int height);
|
||||
void DeterminateChannelLogoSize(int &width, int &height);
|
||||
private:
|
||||
};
|
||||
|
||||
#endif //__NOPACITY_IMAGELOADER_H
|
162
libcore/imagemagickwrapper.c
Normal file
@ -0,0 +1,162 @@
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include "imagemagickwrapper.h"
|
||||
#include "../config.h"
|
||||
#include "imagescaler.h"
|
||||
|
||||
cImageMagickWrapper::cImageMagickWrapper() {
|
||||
InitializeMagick(NULL);
|
||||
}
|
||||
|
||||
cImageMagickWrapper::~cImageMagickWrapper() {
|
||||
}
|
||||
|
||||
cImage *cImageMagickWrapper::CreateImage(int width, int height, bool preserveAspect) {
|
||||
int w, h;
|
||||
w = buffer.columns();
|
||||
h = buffer.rows();
|
||||
if (width == 0)
|
||||
width = w;
|
||||
if (height == 0)
|
||||
height = h;
|
||||
if (preserveAspect) {
|
||||
unsigned scale_w = 1000 * width / w;
|
||||
unsigned scale_h = 1000 * height / h;
|
||||
if (scale_w > scale_h)
|
||||
width = w * height / h;
|
||||
else
|
||||
height = h * width / w;
|
||||
}
|
||||
const PixelPacket *pixels = buffer.getConstPixels(0, 0, w, h);
|
||||
cImage *image = new cImage(cSize(width, height));
|
||||
tColor *imgData = (tColor *)image->Data();
|
||||
if (w != width || h != height) {
|
||||
ImageScaler scaler;
|
||||
scaler.SetImageParameters(imgData, width, width, height, w, h);
|
||||
for (const void *pixels_end = &pixels[w*h]; pixels < pixels_end; ++pixels)
|
||||
scaler.PutSourcePixel(pixels->blue / ((MaxRGB + 1) / 256),
|
||||
pixels->green / ((MaxRGB + 1) / 256),
|
||||
pixels->red / ((MaxRGB + 1) / 256),
|
||||
~((unsigned char)(pixels->opacity / ((MaxRGB + 1) / 256))));
|
||||
return image;
|
||||
}
|
||||
for (const void *pixels_end = &pixels[width*height]; pixels < pixels_end; ++pixels)
|
||||
*imgData++ = ((~int(pixels->opacity / ((MaxRGB + 1) / 256)) << 24) |
|
||||
(int(pixels->green / ((MaxRGB + 1) / 256)) << 8) |
|
||||
(int(pixels->red / ((MaxRGB + 1) / 256)) << 16) |
|
||||
(int(pixels->blue / ((MaxRGB + 1) / 256)) ));
|
||||
return image;
|
||||
}
|
||||
|
||||
cImage cImageMagickWrapper::CreateImageCopy() {
|
||||
int w, h;
|
||||
w = buffer.columns();
|
||||
h = buffer.rows();
|
||||
cImage image (cSize(w, h));
|
||||
const PixelPacket *pixels = buffer.getConstPixels(0, 0, w, h);
|
||||
for (int iy = 0; iy < h; ++iy) {
|
||||
for (int ix = 0; ix < w; ++ix) {
|
||||
tColor col = (~int(pixels->opacity * 255 / MaxRGB) << 24)
|
||||
| (int(pixels->green * 255 / MaxRGB) << 8)
|
||||
| (int(pixels->red * 255 / MaxRGB) << 16)
|
||||
| (int(pixels->blue * 255 / MaxRGB) );
|
||||
image.SetPixel(cPoint(ix, iy), col);
|
||||
++pixels;
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
bool cImageMagickWrapper::LoadImage(std::string FileName, std::string Path, std::string Extension) {
|
||||
try {
|
||||
std::stringstream sstrImgFile;
|
||||
sstrImgFile << Path << FileName << "." << Extension;
|
||||
std::string imgFile = sstrImgFile.str();
|
||||
if (config.debugImageLoading)
|
||||
dsyslog("skindesigner: trying to load: %s", imgFile.c_str());
|
||||
buffer.read(imgFile.c_str());
|
||||
if (config.debugImageLoading)
|
||||
dsyslog("skindesigner: %s sucessfully loaded", imgFile.c_str());
|
||||
} catch( Magick::Warning &warning ) {
|
||||
if (config.debugImageLoading)
|
||||
dsyslog("skindesigner: Magick Warning: %s", warning.what());
|
||||
return true;
|
||||
} catch( Magick::Error &error ) {
|
||||
if (config.debugImageLoading)
|
||||
dsyslog("skindesigner: Magick Error: %s", error.what());
|
||||
return false;
|
||||
} catch(...) {
|
||||
if (config.debugImageLoading)
|
||||
dsyslog("skindesigner: an unknown Magick error occured during image loading");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cImageMagickWrapper::LoadImage(const char *fullpath) {
|
||||
if ((fullpath == NULL) || (strlen(fullpath) < 5))
|
||||
return false;
|
||||
try {
|
||||
if (config.debugImageLoading)
|
||||
dsyslog("skindesigner: trying to load: %s", fullpath);
|
||||
buffer.read(fullpath);
|
||||
if (config.debugImageLoading)
|
||||
dsyslog("skindesigner: %s sucessfully loaded", fullpath);
|
||||
} catch( Magick::Warning &warning ) {
|
||||
if (config.debugImageLoading)
|
||||
dsyslog("skindesigner: Magick Warning: %s", warning.what());
|
||||
return true;
|
||||
} catch( Magick::Error &error ) {
|
||||
if (config.debugImageLoading)
|
||||
dsyslog("skindesigner: Magick Error: %s", error.what());
|
||||
return false;
|
||||
} catch(...) {
|
||||
if (config.debugImageLoading)
|
||||
dsyslog("skindesigner: an unknown Magick error occured during image loading");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Color cImageMagickWrapper::Argb2Color(tColor col) {
|
||||
tIndex alpha = (col & 0xFF000000) >> 24;
|
||||
tIndex red = (col & 0x00FF0000) >> 16;
|
||||
tIndex green = (col & 0x0000FF00) >> 8;
|
||||
tIndex blue = (col & 0x000000FF);
|
||||
Color color(MaxRGB*red/255, MaxRGB*green/255, MaxRGB*blue/255, MaxRGB*(0xFF-alpha)/255);
|
||||
return color;
|
||||
}
|
||||
|
||||
void cImageMagickWrapper::CreateGradient(tColor back, tColor blend, int width, int height, double wfactor, double hfactor) {
|
||||
Color Back = Argb2Color(back);
|
||||
Color Blend = Argb2Color(blend);
|
||||
int maxw = MaxRGB * wfactor;
|
||||
int maxh = MaxRGB * hfactor;
|
||||
|
||||
Image imgblend(Geometry(width, height), Blend);
|
||||
imgblend.modifyImage();
|
||||
imgblend.type(TrueColorMatteType);
|
||||
PixelPacket *pixels = imgblend.getPixels(0, 0, width, height);
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
PixelPacket *pixel = pixels + y * width + x;
|
||||
int opacity = (maxw / width * x + maxh - maxh / height * y) / 2;
|
||||
pixel->opacity = (opacity <= MaxRGB) ? opacity : MaxRGB;
|
||||
}
|
||||
}
|
||||
imgblend.syncPixels();
|
||||
|
||||
Image imgback(Geometry(width, height), Back);
|
||||
imgback.composite(imgblend, 0, 0, OverCompositeOp);
|
||||
|
||||
buffer = imgback;
|
||||
}
|
||||
|
||||
void cImageMagickWrapper::CreateBackground(tColor back, tColor blend, int width, int height, bool mirror) {
|
||||
CreateGradient(back, blend, width, height, 0.8, 0.8);
|
||||
if (mirror)
|
||||
buffer.flop();
|
||||
}
|
||||
void cImageMagickWrapper::CreateBackgroundReverse(tColor back, tColor blend, int width, int height) {
|
||||
CreateGradient(back, blend, width, height, 1.3, 0.7);
|
||||
}
|
28
libcore/imagemagickwrapper.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef __NOPACITY_IMAGEMAGICKWRAPPER_H
|
||||
#define __NOPACITY_IMAGEMAGICKWRAPPER_H
|
||||
|
||||
#define X_DISPLAY_MISSING
|
||||
|
||||
#include <Magick++.h>
|
||||
#include <vdr/osd.h>
|
||||
|
||||
using namespace Magick;
|
||||
|
||||
class cImageMagickWrapper {
|
||||
private:
|
||||
void CreateGradient(tColor back, tColor blend, int width, int height, double wfactor, double hfactor);
|
||||
public:
|
||||
cImageMagickWrapper();
|
||||
~cImageMagickWrapper();
|
||||
protected:
|
||||
Image buffer;
|
||||
Color Argb2Color(tColor col);
|
||||
cImage *CreateImage(int width, int height, bool preserveAspect = true);
|
||||
cImage CreateImageCopy(void);
|
||||
bool LoadImage(std::string FileName, std::string Path, std::string Extension);
|
||||
bool LoadImage(const char *fullpath);
|
||||
void CreateBackground(tColor back, tColor blend, int width, int height, bool mirror = false);
|
||||
void CreateBackgroundReverse(tColor back, tColor blend, int width, int height);
|
||||
};
|
||||
|
||||
#endif //__NOPACITY_IMAGEMAGICKWRAPPER_H
|
149
libcore/imagescaler.c
Normal file
@ -0,0 +1,149 @@
|
||||
|
||||
#include "imagescaler.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
|
||||
ImageScaler::ImageScaler() :
|
||||
m_memory(NULL),
|
||||
m_hor_filters(NULL),
|
||||
m_ver_filters(NULL),
|
||||
m_buffer(NULL),
|
||||
m_dst_image(NULL),
|
||||
m_dst_stride(0),
|
||||
m_dst_width(0),
|
||||
m_dst_height(0),
|
||||
m_src_width(0),
|
||||
m_src_height(0),
|
||||
m_src_x(0),
|
||||
m_src_y(0),
|
||||
m_dst_x(0),
|
||||
m_dst_y(0) {
|
||||
}
|
||||
|
||||
ImageScaler::~ImageScaler() {
|
||||
if ( m_memory ) free( m_memory );
|
||||
}
|
||||
|
||||
// sin(x)/(x)
|
||||
static float sincf( float x ) {
|
||||
if ( fabsf(x) < 0.05f ) return 1.0f - (1.0f/6.0f)*x*x; // taylor series approximation to avoid 0/0
|
||||
return sin(x)/x;
|
||||
}
|
||||
|
||||
static void CalculateFilters( ImageScaler::Filter *filters, int dst_size, int src_size ) {
|
||||
const float fc = dst_size >= src_size ? 1.0f : ((float) dst_size)/((float) src_size);
|
||||
|
||||
for (int i = 0; i < dst_size; i++) {
|
||||
const int d = 2*dst_size; // sample position denominator
|
||||
const int e = (2*i+1) * src_size - dst_size; // sample position enumerator
|
||||
int offset = e / d; // truncated sample position
|
||||
const float sub_offset = ((float) (e - offset*d)) / ((float) d); // exact sample position is (float) e/d = offset + sub_offset
|
||||
|
||||
// calculate filter coefficients
|
||||
float h[4];
|
||||
for (int j=0; j<4; j++) {
|
||||
const float t = 3.14159265359f * (sub_offset+(1-j));
|
||||
h[j] = sincf( fc * t ) * cosf( 0.25f * t ); // sinc-lowpass and cos-window
|
||||
}
|
||||
|
||||
// ensure that filter does not reach out off image bounds:
|
||||
while ( offset < 1 ) {
|
||||
h[0] += h[1];
|
||||
h[1] = h[2];
|
||||
h[2] = h[3];
|
||||
h[3] = 0.0f;
|
||||
offset++;
|
||||
}
|
||||
|
||||
while ( offset+3 > src_size ) {
|
||||
h[3] += h[2];
|
||||
h[2] = h[1];
|
||||
h[1] = h[0];
|
||||
h[0] = 0.0f;
|
||||
offset--;
|
||||
}
|
||||
|
||||
// coefficients are normalized to sum up to 2048
|
||||
const float norm = 2048.0f / ( h[0] + h[1] + h[2] + h[3] );
|
||||
|
||||
offset--; // offset of fist used pixel
|
||||
|
||||
filters[i].m_offset = offset + 4; // store offset of first unused pixel
|
||||
|
||||
for (int j=0; j<4; j++) {
|
||||
const float t = norm * h[j];
|
||||
filters[i].m_coeff[(offset+j) & 3] = (int) ((t > 0.0f) ? (t+0.5f) : (t-0.5f)); // consider ring buffer index permutations
|
||||
}
|
||||
}
|
||||
|
||||
// set end marker
|
||||
filters[dst_size].m_offset = (unsigned) -1;
|
||||
|
||||
}
|
||||
|
||||
void ImageScaler::SetImageParameters( unsigned *dst_image, unsigned dst_stride, unsigned dst_width, unsigned dst_height, unsigned src_width, unsigned src_height ) {
|
||||
m_src_x = 0;
|
||||
m_src_y = 0;
|
||||
m_dst_x = 0;
|
||||
m_dst_y = 0;
|
||||
|
||||
m_dst_image = dst_image;
|
||||
m_dst_stride = dst_stride;
|
||||
|
||||
// if image dimensions do not change we can keep the old filter coefficients
|
||||
if ( (src_width == m_src_width) && (src_height == m_src_height) && (dst_width == m_dst_width) && (dst_height == m_dst_height) ) return;
|
||||
|
||||
m_dst_width = dst_width;
|
||||
m_dst_height = dst_height;
|
||||
m_src_width = src_width;
|
||||
m_src_height = src_height;
|
||||
|
||||
if ( m_memory ) free( m_memory );
|
||||
|
||||
const unsigned hor_filters_size = (m_dst_width + 1) * sizeof(Filter); // reserve one extra position for end marker
|
||||
const unsigned ver_filters_size = (m_dst_height + 1) * sizeof(Filter);
|
||||
const unsigned buffer_size = 4 * m_dst_width * sizeof(TmpPixel);
|
||||
|
||||
char *p = (char *) malloc( hor_filters_size + ver_filters_size + buffer_size );
|
||||
|
||||
m_memory = p;
|
||||
|
||||
m_hor_filters = (Filter *) p; p += hor_filters_size;
|
||||
m_ver_filters = (Filter *) p; p += ver_filters_size;
|
||||
m_buffer = (TmpPixel *) p;
|
||||
|
||||
CalculateFilters( m_hor_filters, m_dst_width , m_src_width );
|
||||
CalculateFilters( m_ver_filters, m_dst_height, m_src_height );
|
||||
}
|
||||
|
||||
// shift range to 0..255 and clamp overflows
|
||||
static unsigned shift_clamp( int x ) {
|
||||
x = ( x + (1<<21) ) >> 22;
|
||||
if ( x < 0 ) return 0;
|
||||
if ( x > 255 ) return 255;
|
||||
return x;
|
||||
}
|
||||
|
||||
void ImageScaler::NextSourceLine() {
|
||||
m_dst_x = 0;
|
||||
m_src_x = 0;
|
||||
m_src_y++;
|
||||
|
||||
while ( m_ver_filters[m_dst_y].m_offset == m_src_y ) {
|
||||
const int h0 = m_ver_filters[m_dst_y].m_coeff[0];
|
||||
const int h1 = m_ver_filters[m_dst_y].m_coeff[1];
|
||||
const int h2 = m_ver_filters[m_dst_y].m_coeff[2];
|
||||
const int h3 = m_ver_filters[m_dst_y].m_coeff[3];
|
||||
const TmpPixel *src = m_buffer;
|
||||
unsigned *dst = m_dst_image + m_dst_stride * m_dst_y;
|
||||
|
||||
for (unsigned i=0; i<m_dst_width; i++) {
|
||||
const ImageScaler::TmpPixel t( src[0]*h0 + src[1]*h1 + src[2]*h2 + src[3]*h3 );
|
||||
src += 4;
|
||||
dst[i] = shift_clamp(t[0]) | (shift_clamp(t[1])<<8) | (shift_clamp(t[2])<<16) | (shift_clamp(t[3])<<24);
|
||||
}
|
||||
|
||||
m_dst_y++;
|
||||
}
|
||||
}
|
97
libcore/imagescaler.h
Normal file
@ -0,0 +1,97 @@
|
||||
#ifndef _ImageScaler_h
|
||||
#define _ImageScaler_h
|
||||
|
||||
/*!
|
||||
* this class scales images consisting of 4 components (RGBA)
|
||||
* to an arbitrary size using a 4-tap filter
|
||||
*/
|
||||
class ImageScaler {
|
||||
public:
|
||||
|
||||
struct Filter {
|
||||
unsigned m_offset;
|
||||
short m_coeff[4];
|
||||
};
|
||||
|
||||
ImageScaler();
|
||||
~ImageScaler();
|
||||
|
||||
//! set destination image and source image size
|
||||
void SetImageParameters( unsigned *dst_image, unsigned dst_stride, unsigned dst_width, unsigned dst_height, unsigned src_width, unsigned src_height );
|
||||
|
||||
/*! process one pixel of source image; destination image is written while input is processed
|
||||
* SetImageParameters() must be called first
|
||||
*/
|
||||
void PutSourcePixel( unsigned char c0, unsigned char c1, unsigned char c2, unsigned char c3 ) {
|
||||
m_hbuf[ (m_src_x++) & 3 ].Set( c0, c1, c2, c3 );
|
||||
|
||||
TmpPixel *bp = m_buffer + 4 * m_dst_x + (m_src_y & 3);
|
||||
const Filter *fh;
|
||||
|
||||
while ( (fh=m_hor_filters+m_dst_x)->m_offset == m_src_x ) {
|
||||
*bp = m_hbuf[0]*fh->m_coeff[0] + m_hbuf[1]*fh->m_coeff[1] + m_hbuf[2]*fh->m_coeff[2] + m_hbuf[3]*fh->m_coeff[3];
|
||||
m_dst_x++;
|
||||
bp += 4;
|
||||
}
|
||||
|
||||
if ( m_src_x == m_src_width ) NextSourceLine();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//! temporary image pixel class - a 4-element integer vector
|
||||
class TmpPixel {
|
||||
public:
|
||||
TmpPixel() {
|
||||
}
|
||||
|
||||
TmpPixel( int c0, int c1, int c2, int c3 ) {
|
||||
Set(c0,c1,c2,c3);
|
||||
}
|
||||
|
||||
void Set( int c0, int c1, int c2, int c3 ) {
|
||||
m_comp[0] = c0;
|
||||
m_comp[1] = c1;
|
||||
m_comp[2] = c2;
|
||||
m_comp[3] = c3;
|
||||
}
|
||||
|
||||
TmpPixel operator*( int s ) const {
|
||||
return TmpPixel( m_comp[0]*s, m_comp[1]*s, m_comp[2]*s, m_comp[3]*s );
|
||||
}
|
||||
|
||||
TmpPixel operator+( const TmpPixel &x ) const {
|
||||
return TmpPixel( m_comp[0] + x[0], m_comp[1] + x[1], m_comp[2] + x[2], m_comp[3] + x[3] );
|
||||
}
|
||||
|
||||
// return component i=[0..3] - No range check!
|
||||
int operator[](unsigned i) const {
|
||||
return m_comp[i];
|
||||
}
|
||||
|
||||
private:
|
||||
int m_comp[4];
|
||||
};
|
||||
|
||||
//! this is called whenever one input line is processed completely
|
||||
void NextSourceLine();
|
||||
|
||||
TmpPixel m_hbuf[4]; //! ring buffer for 4 input pixels
|
||||
char *m_memory; //! buffer container
|
||||
Filter *m_hor_filters; //! buffer for horizontal filters (one for each output image column)
|
||||
Filter *m_ver_filters; //! buffer for vertical filters (one for each output image row)
|
||||
TmpPixel *m_buffer; //! buffer contains 4 horizontally filtered input lines, multiplexed
|
||||
unsigned *m_dst_image; //! pointer to destination image
|
||||
unsigned m_dst_stride; //! destination image stride
|
||||
unsigned m_dst_width; //! destination image width
|
||||
unsigned m_dst_height; //! destination image height
|
||||
unsigned m_src_width; //! source image width
|
||||
unsigned m_src_height; //! source image height
|
||||
unsigned m_src_x; //! x position of next source image pixel
|
||||
unsigned m_src_y; //! y position of source image line currently beeing processed
|
||||
unsigned m_dst_x; //! x position of next destination image pixel
|
||||
unsigned m_dst_y; //! x position of next destination image line
|
||||
};
|
||||
|
||||
#endif // _ImageScaler_h
|
||||
|
477
libcore/pixmapcontainer.c
Normal file
@ -0,0 +1,477 @@
|
||||
#define __STL_CONFIG_H
|
||||
#include "pixmapcontainer.h"
|
||||
#include "../config.h"
|
||||
|
||||
cMutex cPixmapContainer::mutex;
|
||||
cOsd *cPixmapContainer::osd = NULL;
|
||||
eFlushState cPixmapContainer::flushState = fsOpen;
|
||||
|
||||
cPixmapContainer::cPixmapContainer(int numPixmaps) {
|
||||
this->numPixmaps = numPixmaps;
|
||||
pixContainerInit = true;
|
||||
mutex.Lock();
|
||||
pixmaps = new cPixmap*[numPixmaps];
|
||||
pixmapsTransparency = new int[numPixmaps];
|
||||
for(int i=0; i < numPixmaps; i++) {
|
||||
pixmaps[i] = NULL;
|
||||
pixmapsTransparency[i] = 0;
|
||||
}
|
||||
mutex.Unlock();
|
||||
checkRunning = false;
|
||||
fadeTime = 0;
|
||||
deleteOsdOnExit = false;
|
||||
}
|
||||
|
||||
cPixmapContainer::~cPixmapContainer(void) {
|
||||
for (int i=0; i < numPixmaps; i++) {
|
||||
mutex.Lock();
|
||||
if (pixmaps[i] && osd) {
|
||||
osd->DestroyPixmap(pixmaps[i]);
|
||||
pixmaps[i] = NULL;
|
||||
}
|
||||
mutex.Unlock();
|
||||
}
|
||||
delete[] pixmaps;
|
||||
delete[] pixmapsTransparency;
|
||||
if (deleteOsdOnExit && osd) {
|
||||
mutex.Lock();
|
||||
delete osd;
|
||||
osd = NULL;
|
||||
mutex.Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
bool cPixmapContainer::CreateOsd(int Left, int Top, int Width, int Height) {
|
||||
if (osd) {
|
||||
return true;
|
||||
}
|
||||
cOsd *newOsd = cOsdProvider::NewOsd(Left, Top);
|
||||
if (newOsd) {
|
||||
tArea Area = { 0, 0, Width, Height, 32 };
|
||||
if (newOsd->SetAreas(&Area, 1) == oeOk) {
|
||||
osd = newOsd;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cPixmapContainer::LockFlush(void) {
|
||||
flushState = fsLock;
|
||||
}
|
||||
|
||||
void cPixmapContainer::OpenFlush(void) {
|
||||
flushState = fsOpen;
|
||||
}
|
||||
|
||||
bool cPixmapContainer::PixmapExists(int num) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (pixmaps[num])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void cPixmapContainer::DoFlush(void) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!osd || (checkRunning && !Running()))
|
||||
return;
|
||||
if (flushState == fsOpen) {
|
||||
osd->Flush();
|
||||
}
|
||||
}
|
||||
|
||||
void cPixmapContainer::CreatePixmap(int num, int Layer, const cRect &ViewPort, const cRect &DrawPort) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!osd || (checkRunning && !Running()))
|
||||
return;
|
||||
pixmaps[num] = osd->CreatePixmap(Layer, ViewPort, DrawPort);
|
||||
pixmaps[num]->Fill(clrTransparent);
|
||||
if (pixContainerInit && fadeTime) {
|
||||
pixmaps[num]->SetAlpha(0);
|
||||
} else if (pixmapsTransparency[num] > 0) {
|
||||
int alpha = (100 - pixmapsTransparency[num])*255/100;
|
||||
pixmaps[num]->SetAlpha(alpha);
|
||||
}
|
||||
}
|
||||
|
||||
bool cPixmapContainer::DestroyPixmap(int num) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (pixmaps[num] && osd) {
|
||||
osd->DestroyPixmap(pixmaps[num]);
|
||||
pixmaps[num] = NULL;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cPixmapContainer::DrawText(int num, const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, std::string fontName, int fontSize) {
|
||||
if (checkRunning && !Running())
|
||||
return;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return;
|
||||
fontManager->Lock();
|
||||
cFont *font = fontManager->Font(fontName, fontSize);
|
||||
if (font)
|
||||
pixmaps[num]->DrawText(Point, s, ColorFg, ColorBg, font);
|
||||
fontManager->Unlock();
|
||||
}
|
||||
|
||||
|
||||
void cPixmapContainer::DrawRectangle(int num, const cRect &Rect, tColor Color) {
|
||||
if (checkRunning && !Running())
|
||||
return;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return;
|
||||
pixmaps[num]->DrawRectangle(Rect, Color);
|
||||
}
|
||||
|
||||
void cPixmapContainer::DrawEllipse(int num, const cRect &Rect, tColor Color, int Quadrants) {
|
||||
if (checkRunning && !Running())
|
||||
return;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return;
|
||||
pixmaps[num]->DrawEllipse(Rect, Color, Quadrants);
|
||||
}
|
||||
|
||||
void cPixmapContainer::DrawImage(int num, const cPoint &Point, const cImage &Image) {
|
||||
if (checkRunning && !Running())
|
||||
return;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return;
|
||||
pixmaps[num]->DrawImage(Point, Image);
|
||||
}
|
||||
|
||||
void cPixmapContainer::DrawBitmap(int num, const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool Overlay) {
|
||||
if (checkRunning && !Running())
|
||||
return;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return;
|
||||
pixmaps[num]->DrawBitmap(Point, Bitmap, ColorFg, ColorBg, Overlay);
|
||||
}
|
||||
|
||||
void cPixmapContainer::Fill(int num, tColor Color) {
|
||||
if (checkRunning && !Running())
|
||||
return;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return;
|
||||
pixmaps[num]->Fill(Color);
|
||||
}
|
||||
|
||||
void cPixmapContainer::SetAlpha(int num, int Alpha) {
|
||||
if (checkRunning && !Running())
|
||||
return;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return;
|
||||
pixmaps[num]->SetAlpha(Alpha);
|
||||
}
|
||||
|
||||
void cPixmapContainer::SetTransparency(int num, int Transparency) {
|
||||
if (Transparency < 0 && Transparency > 100)
|
||||
return;
|
||||
pixmapsTransparency[num] = Transparency;
|
||||
}
|
||||
|
||||
void cPixmapContainer::SetLayer(int num, int Layer) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return;
|
||||
pixmaps[num]->SetLayer(Layer);
|
||||
}
|
||||
|
||||
int cPixmapContainer::Width(int num) {
|
||||
if (checkRunning && !Running())
|
||||
return 0;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return 0;
|
||||
int width = pixmaps[num]->ViewPort().Width();
|
||||
return width;
|
||||
}
|
||||
|
||||
int cPixmapContainer::Height(int num) {
|
||||
if (checkRunning && !Running())
|
||||
return 0;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return 0;
|
||||
int height = pixmaps[num]->ViewPort().Height();
|
||||
return height;
|
||||
}
|
||||
|
||||
int cPixmapContainer::DrawportWidth(int num) {
|
||||
if (checkRunning && !Running())
|
||||
return 0;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return 0;
|
||||
int width = pixmaps[num]->DrawPort().Width();
|
||||
return width;
|
||||
}
|
||||
|
||||
int cPixmapContainer::DrawportHeight(int num) {
|
||||
if (checkRunning && !Running())
|
||||
return 0;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return 0;
|
||||
int height = pixmaps[num]->DrawPort().Height();
|
||||
return height;
|
||||
}
|
||||
|
||||
int cPixmapContainer::DrawportX(int num) {
|
||||
if (checkRunning && !Running())
|
||||
return 0;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return 0;
|
||||
int x = pixmaps[num]->DrawPort().X();
|
||||
return x;
|
||||
}
|
||||
|
||||
int cPixmapContainer::DrawportY(int num) {
|
||||
if (checkRunning && !Running())
|
||||
return 0;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return 0;
|
||||
int y = pixmaps[num]->DrawPort().Y();
|
||||
return y;
|
||||
}
|
||||
|
||||
void cPixmapContainer::SetDrawPortPoint(int num, const cPoint &Point) {
|
||||
if (checkRunning && !Running())
|
||||
return;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return;
|
||||
pixmaps[num]->SetDrawPortPoint(Point);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* HELPERS -- do not access the pixmaps array directly, use wrapper functions
|
||||
* to ensure that a proper lock is set before accessing pixmaps
|
||||
****************************************************************************/
|
||||
|
||||
void cPixmapContainer::FadeIn(void) {
|
||||
if (!fadeTime)
|
||||
return;
|
||||
uint64_t Start = cTimeMs::Now();
|
||||
int FadeFrameTime = fadeTime / 10;
|
||||
while (Running()) {
|
||||
uint64_t Now = cTimeMs::Now();
|
||||
double t = min(double(Now - Start) / fadeTime, 1.0);
|
||||
int Alpha = t * ALPHA_OPAQUE;
|
||||
for (int i = 0; i < numPixmaps; i++) {
|
||||
if (!PixmapExists(i))
|
||||
continue;
|
||||
if (pixmapsTransparency[i] > 0) {
|
||||
int alpha = (100 - pixmapsTransparency[i])*Alpha/100;
|
||||
SetAlpha(i, alpha);
|
||||
} else {
|
||||
SetAlpha(i, Alpha);
|
||||
}
|
||||
}
|
||||
DoFlush();
|
||||
int Delta = cTimeMs::Now() - Now;
|
||||
if (Running() && (Delta < FadeFrameTime))
|
||||
cCondWait::SleepMs(FadeFrameTime - Delta);
|
||||
if ((int)(Now - Start) > fadeTime)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void cPixmapContainer::FadeOut(void) {
|
||||
if (!fadeTime)
|
||||
return;
|
||||
uint64_t Start = cTimeMs::Now();
|
||||
int FadeFrameTime = fadeTime / 10;
|
||||
while (true) {
|
||||
uint64_t Now = cTimeMs::Now();
|
||||
double t = min(double(Now - Start) / fadeTime, 1.0);
|
||||
int Alpha = (1 - t) * ALPHA_OPAQUE;
|
||||
for (int i = 0; i < numPixmaps; i++) {
|
||||
if (!PixmapExists(i))
|
||||
continue;
|
||||
if (pixmapsTransparency[i] > 0) {
|
||||
int alpha = (100 - pixmapsTransparency[i])*Alpha/100;
|
||||
SetAlpha(i, alpha);
|
||||
} else {
|
||||
SetAlpha(i, Alpha);
|
||||
}
|
||||
}
|
||||
DoFlush();
|
||||
int Delta = cTimeMs::Now() - Now;
|
||||
if (Running() && (Delta < FadeFrameTime))
|
||||
cCondWait::SleepMs(FadeFrameTime - Delta);
|
||||
if ((int)(Now - Start) > fadeTime)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* scrollSpeed: 1 slow
|
||||
* 2 medium
|
||||
* 3 fast
|
||||
******************************************/
|
||||
void cPixmapContainer::ScrollHorizontal(int num, int scrollDelay, int scrollSpeed, int scrollMode) {
|
||||
bool carriageReturn = (scrollMode == 1) ? true : false;
|
||||
|
||||
int scrollDelta = 1;
|
||||
int drawPortX;
|
||||
|
||||
int FrameTime = 0;
|
||||
if (scrollSpeed == 1)
|
||||
FrameTime = 50;
|
||||
else if (scrollSpeed == 2)
|
||||
FrameTime = 30;
|
||||
else
|
||||
FrameTime = 15;
|
||||
if (!Running())
|
||||
return;
|
||||
int maxX = DrawportWidth(num) - Width(num);
|
||||
bool doSleep = false;
|
||||
while (Running()) {
|
||||
if (doSleep) {
|
||||
DoSleep(scrollDelay);
|
||||
doSleep = false;
|
||||
}
|
||||
if (!Running())
|
||||
return;
|
||||
uint64_t Now = cTimeMs::Now();
|
||||
drawPortX = DrawportX(num);
|
||||
drawPortX -= scrollDelta;
|
||||
|
||||
if (abs(drawPortX) > maxX) {
|
||||
DoSleep(scrollDelay);
|
||||
if (carriageReturn)
|
||||
drawPortX = 0;
|
||||
else {
|
||||
scrollDelta *= -1;
|
||||
drawPortX -= scrollDelta;
|
||||
}
|
||||
doSleep = true;
|
||||
}
|
||||
if (!carriageReturn && (drawPortX == 0)) {
|
||||
scrollDelta *= -1;
|
||||
doSleep = true;
|
||||
}
|
||||
SetDrawPortPoint(num, cPoint(drawPortX, 0));
|
||||
int Delta = cTimeMs::Now() - Now;
|
||||
DoFlush();
|
||||
if (Running() && (Delta < FrameTime))
|
||||
cCondWait::SleepMs(FrameTime - Delta);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* scrollSpeed: 1 slow
|
||||
* 2 medium
|
||||
* 3 fast
|
||||
******************************************/
|
||||
void cPixmapContainer::ScrollVertical(int num, int scrollDelay, int scrollSpeed) {
|
||||
if (!scrollSpeed)
|
||||
return;
|
||||
DoSleep(scrollDelay);
|
||||
int drawPortY;
|
||||
int FrameTime = 0;
|
||||
if (scrollSpeed == 1)
|
||||
FrameTime = 50;
|
||||
else if (scrollSpeed == 2)
|
||||
FrameTime = 30;
|
||||
else
|
||||
FrameTime = 15;
|
||||
int maxY = DrawportHeight(num) - Height(num);
|
||||
bool doSleep = false;
|
||||
while (Running()) {
|
||||
if (doSleep) {
|
||||
doSleep = false;
|
||||
DoSleep(scrollDelay);
|
||||
}
|
||||
uint64_t Now = cTimeMs::Now();
|
||||
drawPortY = DrawportY(num);
|
||||
drawPortY -= 1;
|
||||
if (abs(drawPortY) > maxY) {
|
||||
doSleep = true;
|
||||
DoSleep(scrollDelay);
|
||||
drawPortY = 0;
|
||||
}
|
||||
SetDrawPortPoint(num, cPoint(0, drawPortY));
|
||||
if (doSleep) {
|
||||
DoSleep(scrollDelay);
|
||||
}
|
||||
int Delta = cTimeMs::Now() - Now;
|
||||
DoFlush();
|
||||
if (Running() && (Delta < FrameTime))
|
||||
cCondWait::SleepMs(FrameTime - Delta);
|
||||
}
|
||||
}
|
||||
|
||||
void cPixmapContainer::CancelSave(void) {
|
||||
Cancel(-1);
|
||||
while (Active())
|
||||
cCondWait::SleepMs(10);
|
||||
}
|
||||
|
||||
void cPixmapContainer::DoSleep(int duration) {
|
||||
int sleepSlice = 10;
|
||||
for (int i = 0; Running() && (i*sleepSlice < duration); i++)
|
||||
cCondWait::SleepMs(sleepSlice);
|
||||
}
|
||||
|
||||
void cPixmapContainer::DrawBlendedBackground(int num, int xStart, int width, tColor color, tColor colorBlending, bool fromTop) {
|
||||
int height = Height(num);
|
||||
int numSteps = 16;
|
||||
int alphaStep = 0x0F;
|
||||
int alpha = 0x00;
|
||||
int step, begin, end;
|
||||
if (fromTop) {
|
||||
step = 1;
|
||||
begin = 0;
|
||||
end = numSteps;
|
||||
} else {
|
||||
step = -1;
|
||||
begin = height;
|
||||
end = height - numSteps;
|
||||
}
|
||||
tColor clr;
|
||||
bool cont = true;
|
||||
for (int i = begin; cont; i = i + step) {
|
||||
clr = AlphaBlend(color, colorBlending, alpha);
|
||||
DrawRectangle(num, cRect(xStart,i,width,1), clr);
|
||||
alpha += alphaStep;
|
||||
if (i == end)
|
||||
cont = false;
|
||||
}
|
||||
}
|
||||
|
||||
void cPixmapContainer::DrawRoundedCorners(int num, int radius, int x, int y, int width, int height) {
|
||||
if (radius > 2) {
|
||||
DrawEllipse(num, cRect(x, y, radius, radius), clrTransparent, -2);
|
||||
DrawEllipse(num, cRect(x + width - radius, y , radius, radius), clrTransparent, -1);
|
||||
DrawEllipse(num, cRect(x, y + height - radius, radius, radius), clrTransparent, -3);
|
||||
DrawEllipse(num, cRect(x + width - radius, y + height - radius, radius, radius), clrTransparent, -4);
|
||||
}
|
||||
}
|
||||
|
||||
void cPixmapContainer::DrawRoundedCornersWithBorder(int num, tColor borderColor, int radius, int width, int height) {
|
||||
if (radius < 3)
|
||||
return;
|
||||
DrawEllipse(num, cRect(0,0,radius,radius), borderColor, -2);
|
||||
DrawEllipse(num, cRect(-1,-1,radius,radius), clrTransparent, -2);
|
||||
|
||||
DrawEllipse(num, cRect(width-radius,0,radius,radius), borderColor, -1);
|
||||
DrawEllipse(num, cRect(width-radius+1,-1,radius,radius), clrTransparent, -1);
|
||||
|
||||
DrawEllipse(num, cRect(0,height-radius,radius,radius), borderColor, -3);
|
||||
DrawEllipse(num, cRect(-1,height-radius+1,radius,radius), clrTransparent, -3);
|
||||
|
||||
DrawEllipse(num, cRect(width-radius,height-radius,radius,radius), borderColor, -4);
|
||||
DrawEllipse(num, cRect(width-radius+1,height-radius+1,radius,radius), clrTransparent, -4);
|
||||
}
|
73
libcore/pixmapcontainer.h
Normal file
@ -0,0 +1,73 @@
|
||||
#ifndef __PIXMAP_CONTAINER_H
|
||||
#define __PIXMAP_CONTAINER_H
|
||||
|
||||
#include <string>
|
||||
#include <vdr/plugin.h>
|
||||
#include "fontmanager.h"
|
||||
|
||||
enum eFlushState {
|
||||
fsOpen,
|
||||
fsLock,
|
||||
fsCount,
|
||||
};
|
||||
|
||||
class cPixmapContainer : public cThread {
|
||||
private:
|
||||
static cMutex mutex;
|
||||
static cOsd *osd;
|
||||
static eFlushState flushState;
|
||||
bool pixContainerInit;
|
||||
int numPixmaps;
|
||||
cPixmap **pixmaps;
|
||||
int *pixmapsTransparency;
|
||||
bool checkRunning;
|
||||
int fadeTime;
|
||||
bool deleteOsdOnExit;
|
||||
protected:
|
||||
void SetInitFinished(void) { pixContainerInit = false; };
|
||||
bool CreateOsd(int Left, int Top, int Width, int Height);
|
||||
void DeleteOsdOnExit(void) { deleteOsdOnExit = true; };
|
||||
void LockFlush(void);
|
||||
void OpenFlush(void);
|
||||
//Wrappers for access to pixmaps
|
||||
bool PixmapExists(int num);
|
||||
int NumPixmaps(void) { return numPixmaps; };
|
||||
void CreatePixmap(int num, int Layer, const cRect &ViewPort, const cRect &DrawPort = cRect::Null);
|
||||
bool DestroyPixmap(int num);
|
||||
void DrawText(int num, const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, std::string fontName, int fontSize);
|
||||
void DrawRectangle(int num, const cRect &Rect, tColor Color);
|
||||
void DrawEllipse(int num, const cRect &Rect, tColor Color, int Quadrants = 0);
|
||||
void DrawImage(int num, const cPoint &Point, const cImage &Image);
|
||||
void DrawBitmap(int num, const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg = 0, tColor ColorBg = 0, bool Overlay = false);
|
||||
void Fill(int num, tColor Color);
|
||||
void SetAlpha(int num, int Alpha);
|
||||
void SetTransparency(int num, int Transparency);
|
||||
void SetLayer(int num, int Layer);
|
||||
int Width(int num);
|
||||
int Height(int num);
|
||||
int DrawportWidth(int num);
|
||||
int DrawportHeight(int num);
|
||||
int DrawportX(int num);
|
||||
int DrawportY(int num);
|
||||
void SetDrawPortPoint(int num, const cPoint &Point);
|
||||
void SetCheckRunning(void) { checkRunning = true; };
|
||||
void UnsetCheckRunning(void) { checkRunning = false; };
|
||||
//HELPERS -- do not access the pixmaps array directly, use wrapper functions
|
||||
void SetFadeTime(int fade) { fadeTime = fade; };
|
||||
void FadeIn(void);
|
||||
void FadeOut(void);
|
||||
void ScrollVertical(int num, int scrollDelay, int scrollSpeed);
|
||||
void ScrollHorizontal(int num, int scrollDelay, int scrollSpeed, int scrollMode);
|
||||
void CancelSave(void);
|
||||
void DoSleep(int duration);
|
||||
void DrawBlendedBackground(int num, int xStart, int width, tColor color, tColor colorBlending, bool fromTop);
|
||||
void DrawRoundedCorners(int num, int radius, int x, int y, int width, int height);
|
||||
void DrawRoundedCornersWithBorder(int num, tColor borderColor, int radius, int width, int height);
|
||||
public:
|
||||
cPixmapContainer(int numPixmaps);
|
||||
virtual ~cPixmapContainer(void);
|
||||
void DoFlush(void);
|
||||
virtual void Action(void) {};
|
||||
};
|
||||
|
||||
#endif //__PIXMAP_CONTAINER_H
|
84
libcore/timers.c
Normal file
@ -0,0 +1,84 @@
|
||||
#include "timers.h"
|
||||
#include "../services/epgsearch.h"
|
||||
#include "../services/remotetimers.h"
|
||||
|
||||
static int CompareTimers(const void *a, const void *b) {
|
||||
return (*(const cTimer **)a)->Compare(**(const cTimer **)b);
|
||||
}
|
||||
|
||||
cGlobalSortedTimers::cGlobalSortedTimers(bool forceRefresh) : cVector<const cTimer *>(Timers.Count()) {
|
||||
static bool initial = true;
|
||||
static cRemoteTimerRefresh *remoteTimerRefresh = NULL;
|
||||
|
||||
if (forceRefresh)
|
||||
initial = true;
|
||||
//check if remotetimers plugin is available
|
||||
static cPlugin* pRemoteTimers = cPluginManager::GetPlugin("remotetimers");
|
||||
|
||||
cSchedulesLock SchedulesLock;
|
||||
const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
|
||||
|
||||
if (pRemoteTimers && initial) {
|
||||
cString errorMsg;
|
||||
pRemoteTimers->Service("RemoteTimers::RefreshTimers-v1.0", &errorMsg);
|
||||
initial = false;
|
||||
}
|
||||
|
||||
for (cTimer *Timer = Timers.First(); Timer; Timer = Timers.Next(Timer))
|
||||
Append(Timer);
|
||||
|
||||
//if remotetimers plugin is available, take timers also from him
|
||||
if (pRemoteTimers) {
|
||||
cTimer* remoteTimer = NULL;
|
||||
while (pRemoteTimers->Service("RemoteTimers::ForEach-v1.0", &remoteTimer) && remoteTimer != NULL) {
|
||||
remoteTimer->SetEventFromSchedule(Schedules); // make sure the event is current
|
||||
Append(remoteTimer);
|
||||
}
|
||||
}
|
||||
|
||||
Sort(CompareTimers);
|
||||
|
||||
if (pRemoteTimers && (remoteTimerRefresh == NULL))
|
||||
remoteTimerRefresh = new cRemoteTimerRefresh();
|
||||
}
|
||||
|
||||
int cGlobalSortedTimers::NumTimerConfilicts(void) {
|
||||
int numConflicts = 0;
|
||||
cPlugin *p = cPluginManager::GetPlugin("epgsearch");
|
||||
if (p) {
|
||||
Epgsearch_lastconflictinfo_v1_0 *serviceData = new Epgsearch_lastconflictinfo_v1_0;
|
||||
if (serviceData) {
|
||||
serviceData->nextConflict = 0;
|
||||
serviceData->relevantConflicts = 0;
|
||||
serviceData->totalConflicts = 0;
|
||||
p->Service("Epgsearch-lastconflictinfo-v1.0", serviceData);
|
||||
if (serviceData->relevantConflicts > 0) {
|
||||
numConflicts = serviceData->relevantConflicts;
|
||||
}
|
||||
delete serviceData;
|
||||
}
|
||||
}
|
||||
return numConflicts;
|
||||
}
|
||||
|
||||
cRemoteTimerRefresh::cRemoteTimerRefresh(): cThread("skindesigner: RemoteTimers::RefreshTimers") {
|
||||
Start();
|
||||
}
|
||||
|
||||
cRemoteTimerRefresh::~cRemoteTimerRefresh(void) {
|
||||
Cancel(-1);
|
||||
while (Active())
|
||||
cCondWait::SleepMs(10);
|
||||
}
|
||||
|
||||
void cRemoteTimerRefresh::Action(void) {
|
||||
#define REFESH_INTERVALL_MS 30000
|
||||
while (Running()) {
|
||||
cCondWait::SleepMs(REFESH_INTERVALL_MS);
|
||||
if (!cOsd::IsOpen()) {//make sure that no timer is currently being edited
|
||||
cGlobalSortedTimers(true);
|
||||
Timers.SetModified();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
20
libcore/timers.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef __NOPACITY_TIMERS_H
|
||||
#define __NOPACITY_TIMERS_H
|
||||
|
||||
#include <vdr/timers.h>
|
||||
#include <vdr/plugin.h>
|
||||
|
||||
class cGlobalSortedTimers : public cVector<const cTimer *> {
|
||||
public:
|
||||
cGlobalSortedTimers(bool forceRefresh = false);
|
||||
int NumTimerConfilicts(void);
|
||||
};
|
||||
|
||||
class cRemoteTimerRefresh: public cThread {
|
||||
protected:
|
||||
virtual void Action(void);
|
||||
public:
|
||||
cRemoteTimerRefresh(void);
|
||||
virtual ~cRemoteTimerRefresh(void);
|
||||
};
|
||||
#endif //__NOPACITY_TIMERS_H
|
98
libtemplate/globals.c
Normal file
@ -0,0 +1,98 @@
|
||||
#include "globals.h"
|
||||
#include "xmlparser.h"
|
||||
#include <locale.h>
|
||||
|
||||
cGlobals::cGlobals(void) {
|
||||
fonts.insert(pair<string, string>("vdrOsd", Setup.FontOsd));
|
||||
fonts.insert(pair<string, string>("vdrFix", Setup.FontFix));
|
||||
fonts.insert(pair<string, string>("vdrSml", Setup.FontSml));
|
||||
|
||||
string loc = setlocale(LC_NAME, NULL);
|
||||
size_t index = loc.find_first_of(".");
|
||||
string langISO = "";
|
||||
if (index > 0) {
|
||||
langISO = loc.substr(0, index);
|
||||
}
|
||||
if (langISO.size() == 5) {
|
||||
language = langISO.c_str();
|
||||
} else {
|
||||
language = "en_EN";
|
||||
}
|
||||
dsyslog("skindesigner: using language %s", language.c_str());
|
||||
}
|
||||
|
||||
bool cGlobals::ReadFromXML(void) {
|
||||
std::string xmlFile = "globals.xml";
|
||||
cXmlParser parser;
|
||||
if (!parser.ReadGlobals(this, xmlFile))
|
||||
return false;
|
||||
if (!parser.ParseGlobals())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cGlobals::Translate(string text, string &translation) {
|
||||
string transStart = "{tr(";
|
||||
string transEnd = ")}";
|
||||
size_t foundStart = text.find(transStart);
|
||||
size_t foundEnd = text.find(transEnd);
|
||||
bool translated = false;
|
||||
|
||||
while (foundStart != string::npos && foundEnd != string::npos) {
|
||||
string token = text.substr(foundStart + 1, foundEnd - foundStart);
|
||||
string transToken = DoTranslate(token);
|
||||
if (transToken.size() > 0)
|
||||
translated = true;
|
||||
else
|
||||
return false;
|
||||
text.replace(foundStart, foundEnd - foundStart + 2, transToken);
|
||||
foundStart = text.find(transStart);
|
||||
foundEnd = text.find(transEnd);
|
||||
}
|
||||
if (translated)
|
||||
translation = text;
|
||||
return translated;
|
||||
}
|
||||
|
||||
string cGlobals::DoTranslate(string token) {
|
||||
string translation = "";
|
||||
map <string, map< string, string > >::iterator hit = translations.find(token);
|
||||
if (hit == translations.end()) {
|
||||
esyslog("skindesigner: invalid translation token %s", token.c_str());
|
||||
return translation;
|
||||
}
|
||||
map< string, string > translats = hit->second;
|
||||
map< string, string >::iterator trans = translats.find(language);
|
||||
if (trans != translats.end()) {
|
||||
translation = trans->second;
|
||||
} else {
|
||||
map< string, string >::iterator transDefault = translats.find("en_EN");
|
||||
if (transDefault != translats.end()) {
|
||||
translation = transDefault->second;
|
||||
}
|
||||
}
|
||||
return translation;
|
||||
}
|
||||
|
||||
void cGlobals::Debug(void) {
|
||||
dsyslog("skindesigner: GLOBAL VARIABLES");
|
||||
for (map <string, tColor>::iterator col = colors.begin(); col != colors.end(); col++) {
|
||||
dsyslog("skindesigner: Color \"%s\": %x", (col->first).c_str(), col->second);
|
||||
}
|
||||
for (map <string, int>::iterator myInt = intVars.begin(); myInt != intVars.end(); myInt++) {
|
||||
dsyslog("skindesigner: Integer Variable \"%s\": %d", (myInt->first).c_str(), myInt->second);
|
||||
}
|
||||
for (map <string, string>::iterator myStr = stringVars.begin(); myStr != stringVars.end(); myStr++) {
|
||||
dsyslog("skindesigner: String Variable \"%s\": \"%s\"", (myStr->first).c_str(), (myStr->second).c_str());
|
||||
}
|
||||
for (map <string, string>::iterator font = fonts.begin(); font != fonts.end(); font++) {
|
||||
dsyslog("skindesigner: Font \"%s\": \"%s\"", (font->first).c_str(), (font->second).c_str());
|
||||
}
|
||||
for (map <string, map< string, string > >::iterator trans = translations.begin(); trans != translations.end(); trans++) {
|
||||
dsyslog("skindesigner: Translation Token %s", (trans->first).c_str());
|
||||
map< string, string > tokenTrans = trans->second;
|
||||
for (map< string, string >::iterator transTok = tokenTrans.begin(); transTok != tokenTrans.end(); transTok++) {
|
||||
dsyslog("skindesigner: language %s, translation %s", (transTok->first).c_str(), (transTok->second).c_str());
|
||||
}
|
||||
}
|
||||
}
|
38
libtemplate/globals.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef __XMLGLOBALS_H
|
||||
#define __XMLGLOBALS_H
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <vdr/plugin.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef uint32_t tColor;
|
||||
|
||||
// --- cGlobals -------------------------------------------------------------
|
||||
|
||||
class cGlobals {
|
||||
private:
|
||||
string language;
|
||||
string DoTranslate(string token);
|
||||
public:
|
||||
cGlobals(void);
|
||||
virtual ~cGlobals(void) {};
|
||||
map <string, tColor> colors;
|
||||
map <string, int> intVars;
|
||||
map <string, string> stringVars;
|
||||
map <string, string> fonts;
|
||||
map <string, map< string, string > > translations;
|
||||
bool ReadFromXML(void);
|
||||
bool Translate(string text, string &translation);
|
||||
void Debug(void);
|
||||
};
|
||||
|
||||
#endif //__XMLGLOBALS_H
|
394
libtemplate/parameter.c
Normal file
@ -0,0 +1,394 @@
|
||||
#include "parameter.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// --- cNumericParameter -------------------------------------------------------------
|
||||
|
||||
cNumericParameter::cNumericParameter(string value) {
|
||||
this->value = value;
|
||||
globals = NULL;
|
||||
isValid = false;
|
||||
width = 0;
|
||||
height = 0;
|
||||
columnWidth = -1;
|
||||
rowHeight = -1;
|
||||
hor = true;
|
||||
defaultValue = 0;
|
||||
}
|
||||
|
||||
cNumericParameter::~cNumericParameter(void) {
|
||||
}
|
||||
|
||||
void cNumericParameter::SetAreaSize(int w, int h) {
|
||||
width = w;
|
||||
height = h;
|
||||
}
|
||||
|
||||
int cNumericParameter::Parse(string &parsedValue) {
|
||||
int retVal = defaultValue;
|
||||
|
||||
if (IsNumber(value)) {
|
||||
isValid = true;
|
||||
retVal = atoi(value.c_str());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//checking for percent value
|
||||
bool isPercentValue = CheckPercentValue(retVal);
|
||||
if (isPercentValue) {
|
||||
isValid = true;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//checking for expression
|
||||
bool isValidExpression = CheckExpression(retVal, parsedValue);
|
||||
if (isValidExpression) {
|
||||
isValid = true;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
bool cNumericParameter::IsNumber(const string& s) {
|
||||
string::const_iterator it = s.begin();
|
||||
while (it != s.end() && isdigit(*it)) ++it;
|
||||
return !s.empty() && it == s.end();
|
||||
}
|
||||
|
||||
bool cNumericParameter::CheckPercentValue(int &val) {
|
||||
bool ok = false;
|
||||
size_t posPercent = value.find('%');
|
||||
if (posPercent != string::npos) {
|
||||
string strPerc = value.substr(0, posPercent);
|
||||
if (!IsNumber(strPerc)) {
|
||||
return ok;
|
||||
}
|
||||
int perc = atoi(strPerc.c_str());
|
||||
if (hor) {
|
||||
val = width * perc / 100;
|
||||
} else {
|
||||
val = height * perc / 100;
|
||||
}
|
||||
ok = true;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool cNumericParameter::CheckExpression(int &val, string &parsedVal) {
|
||||
bool ok = false;
|
||||
string parsedValue = value;
|
||||
//remove white spaces
|
||||
parsedValue.erase( std::remove_if( parsedValue.begin(), parsedValue.end(), ::isspace ), parsedValue.end() );
|
||||
|
||||
//check and replace {areawidth} and {areaheight} tokens
|
||||
string tokenWidth = "{areawidth}";
|
||||
string tokenHeight = "{areaheight}";
|
||||
|
||||
stringstream sw;
|
||||
sw << width;
|
||||
string strWidth = sw.str();
|
||||
stringstream sh;
|
||||
sh << height;
|
||||
string strHeight = sh.str();
|
||||
|
||||
bool foundToken = true;
|
||||
while(foundToken) {
|
||||
size_t foundTokenWidth = parsedValue.find(tokenWidth);
|
||||
if (foundTokenWidth != string::npos) {
|
||||
parsedValue = parsedValue.replace(foundTokenWidth, tokenWidth.size(), strWidth);
|
||||
} else {
|
||||
foundToken = false;
|
||||
}
|
||||
}
|
||||
|
||||
foundToken = true;
|
||||
while(foundToken) {
|
||||
size_t foundTokenHeight = parsedValue.find(tokenHeight);
|
||||
if (foundTokenHeight != string::npos) {
|
||||
parsedValue = parsedValue.replace(foundTokenHeight, tokenHeight.size(), strHeight);
|
||||
} else {
|
||||
foundToken = false;
|
||||
}
|
||||
}
|
||||
|
||||
//check and replace {columnwidth} and {rowheight} tokens for loop functions
|
||||
if (columnWidth > 0 || rowHeight > 0) {
|
||||
tokenWidth = "{columnwidth}";
|
||||
tokenHeight = "{rowheight}";
|
||||
stringstream cw;
|
||||
cw << columnWidth;
|
||||
strWidth = cw.str();
|
||||
stringstream rh;
|
||||
rh << rowHeight;
|
||||
strHeight = rh.str();
|
||||
|
||||
foundToken = true;
|
||||
while(foundToken) {
|
||||
size_t foundTokenWidth = parsedValue.find(tokenWidth);
|
||||
if (foundTokenWidth != string::npos) {
|
||||
parsedValue = parsedValue.replace(foundTokenWidth, tokenWidth.size(), strWidth);
|
||||
} else {
|
||||
foundToken = false;
|
||||
}
|
||||
}
|
||||
|
||||
foundToken = true;
|
||||
while(foundToken) {
|
||||
size_t foundTokenHeight = parsedValue.find(tokenHeight);
|
||||
if (foundTokenHeight != string::npos) {
|
||||
parsedValue = parsedValue.replace(foundTokenHeight, tokenHeight.size(), strHeight);
|
||||
} else {
|
||||
foundToken = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (globals) {
|
||||
for (map<string, int>::iterator globInt = globals->intVars.begin(); globInt != globals->intVars.end(); globInt++) {
|
||||
stringstream sToken;
|
||||
sToken << "{" << globInt->first << "}";
|
||||
string token = sToken.str();
|
||||
size_t foundToken = parsedValue.find(token);
|
||||
if (foundToken != string::npos) {
|
||||
stringstream st;
|
||||
st << globInt->second;
|
||||
parsedValue = parsedValue.replace(foundToken, token.size(), st.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsNumber(parsedValue)) {
|
||||
ok = true;
|
||||
val = atoi(parsedValue.c_str());
|
||||
return ok;
|
||||
}
|
||||
|
||||
if (!ValidNumericExpression(parsedValue)) {
|
||||
parsedVal = parsedValue;
|
||||
return ok;
|
||||
}
|
||||
ok = true;
|
||||
char * expression = new char[parsedValue.size() + 1];
|
||||
std::copy(parsedValue.begin(), parsedValue.end(), expression);
|
||||
expression[parsedValue.size()] = '\0';
|
||||
int expRes = EvaluateTheExpression(expression);
|
||||
val = expRes;
|
||||
delete[] expression;
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool cNumericParameter::ValidNumericExpression(string &parsedValue) {
|
||||
string::const_iterator it = parsedValue.begin();
|
||||
while (it != parsedValue.end() && (isdigit(*it) || *it == '.' || *it == ',' || *it == '+' || *it == '-' || *it == '*' || *it == '/')) ++it;
|
||||
return !parsedValue.empty() && it == parsedValue.end();
|
||||
}
|
||||
|
||||
int cNumericParameter::EvaluateTheExpression(char* expr) {
|
||||
return round(ParseSummands(expr));
|
||||
}
|
||||
|
||||
double cNumericParameter::ParseAtom(char*& expr) {
|
||||
// Read the number from string
|
||||
char* end_ptr;
|
||||
double res = strtod(expr, &end_ptr);
|
||||
// Advance the pointer and return the result
|
||||
expr = end_ptr;
|
||||
return res;
|
||||
}
|
||||
|
||||
// Parse multiplication and division
|
||||
double cNumericParameter::ParseFactors(char*& expr) {
|
||||
double num1 = ParseAtom(expr);
|
||||
for(;;) {
|
||||
// Save the operation
|
||||
char op = *expr;
|
||||
if(op != '/' && op != '*')
|
||||
return num1;
|
||||
expr++;
|
||||
double num2 = ParseAtom(expr);
|
||||
// Perform the saved operation
|
||||
if(op == '/') {
|
||||
if (num2 != 0) {
|
||||
num1 /= num2;
|
||||
}
|
||||
} else
|
||||
num1 *= num2;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse addition and subtraction
|
||||
double cNumericParameter::ParseSummands(char*& expr) {
|
||||
double num1 = ParseFactors(expr);
|
||||
for(;;) {
|
||||
char op = *expr;
|
||||
if(op != '-' && op != '+')
|
||||
return num1;
|
||||
expr++;
|
||||
double num2 = ParseFactors(expr);
|
||||
if(op == '-')
|
||||
num1 -= num2;
|
||||
else
|
||||
num1 += num2;
|
||||
}
|
||||
}
|
||||
|
||||
// --- cConditionalParameter -------------------------------------------------------------
|
||||
|
||||
cConditionalParameter::cConditionalParameter(cGlobals *globals, string value) {
|
||||
this->globals = globals;
|
||||
isTrue = false;
|
||||
this->value = value;
|
||||
type = cpNone;
|
||||
}
|
||||
|
||||
cConditionalParameter::~cConditionalParameter(void) {
|
||||
}
|
||||
|
||||
void cConditionalParameter::Tokenize(void) {
|
||||
size_t posAnd = value.find("++");
|
||||
if (posAnd != string::npos) {
|
||||
type = cpAnd;
|
||||
TokenizeValue("++");
|
||||
} else {
|
||||
size_t posOr = value.find("||");
|
||||
if (posOr != string::npos) {
|
||||
type = cpOr;
|
||||
TokenizeValue("||");
|
||||
}
|
||||
}
|
||||
if (type == cpNone) {
|
||||
InsertCondition(value);
|
||||
}
|
||||
}
|
||||
|
||||
bool cConditionalParameter::Evaluate(map < string, int > *intTokens, map < string, string > *stringTokens) {
|
||||
isTrue = false;
|
||||
bool first = true;
|
||||
for (vector<sCondition>::iterator cond = conditions.begin(); cond != conditions.end(); cond++) {
|
||||
bool tokenTrue = false;
|
||||
|
||||
if (cond->type == ctStringSet) {
|
||||
if (stringTokens) {
|
||||
map < string, string >::iterator hit = stringTokens->find(cond->tokenName);
|
||||
if (hit != stringTokens->end()) {
|
||||
string value = hit->second;
|
||||
if (value.size() > 0)
|
||||
tokenTrue = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int tokenValue = EvaluateParameter(cond->tokenName, intTokens, stringTokens);
|
||||
if (cond->type == ctBool) {
|
||||
tokenTrue = tokenValue;
|
||||
} else if (cond->type == ctGreater) {
|
||||
tokenTrue = (tokenValue > cond->compareValue) ? true : false;
|
||||
} else if (cond->type == ctLower) {
|
||||
tokenTrue = (tokenValue < cond->compareValue) ? true : false;
|
||||
} else if (cond->type == ctEquals) {
|
||||
tokenTrue = (tokenValue == cond->compareValue) ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
if (cond->isNegated)
|
||||
tokenTrue = !tokenTrue;
|
||||
if (type == cpAnd) {
|
||||
if (first)
|
||||
isTrue = tokenTrue;
|
||||
else
|
||||
isTrue = isTrue && tokenTrue;
|
||||
} else if (type == cpOr) {
|
||||
isTrue = isTrue || tokenTrue;
|
||||
} else {
|
||||
isTrue = tokenTrue;
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
int cConditionalParameter::EvaluateParameter(string token, map < string, int > *intTokens, map < string, string > *stringTokens) {
|
||||
//first check globals
|
||||
map < string, int >::iterator hitGlobals = globals->intVars.find(token);
|
||||
if (hitGlobals != globals->intVars.end()) {
|
||||
return hitGlobals->second;
|
||||
} else {
|
||||
//then check tokens
|
||||
if (intTokens) {
|
||||
map < string, int >::iterator hit = intTokens->find(token);
|
||||
if (hit != intTokens->end()) {
|
||||
return hit->second;
|
||||
}
|
||||
}
|
||||
if (stringTokens) {
|
||||
map < string, string >::iterator hit = stringTokens->find(token);
|
||||
if (hit != stringTokens->end()) {
|
||||
string value = hit->second;
|
||||
return atoi(value.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cConditionalParameter::TokenizeValue(string sep) {
|
||||
string buffer = value;
|
||||
bool sepFound = true;
|
||||
while (sepFound) {
|
||||
size_t posSep = buffer.find(sep);
|
||||
if (posSep == string::npos) {
|
||||
InsertCondition(buffer);
|
||||
sepFound = false;
|
||||
}
|
||||
string token = buffer.substr(0, posSep);
|
||||
buffer = buffer.replace(0, posSep + sep.size(), "");
|
||||
InsertCondition(token);
|
||||
}
|
||||
}
|
||||
|
||||
void cConditionalParameter::InsertCondition(string cond) {
|
||||
cond.erase( std::remove_if( cond.begin(), cond.end(), ::isspace ), cond.end() );
|
||||
|
||||
if (cond.size() < 1)
|
||||
return;
|
||||
|
||||
size_t tokenStart = cond.find('{');
|
||||
size_t tokenEnd = cond.find('}');
|
||||
|
||||
if (tokenStart == string::npos || tokenEnd == string::npos || tokenStart > tokenEnd)
|
||||
return;
|
||||
|
||||
string tokenName = cond.substr(tokenStart + 1, tokenEnd - tokenStart - 1);
|
||||
string rest = cond.replace(tokenStart, tokenEnd - tokenStart + 1, "");
|
||||
|
||||
sCondition sCond;
|
||||
sCond.tokenName = tokenName;
|
||||
sCond.type = ctBool;
|
||||
sCond.compareValue = 0;
|
||||
sCond.isNegated = false;
|
||||
if (!rest.compare("not")) {
|
||||
sCond.isNegated = true;
|
||||
} else if (!rest.compare("isset")) {
|
||||
sCond.type = ctStringSet;
|
||||
} else if (startswith(rest.c_str(), "gt(")) {
|
||||
string compVal = rest.substr(4, rest.size() - 5);
|
||||
sCond.compareValue = atoi(compVal.c_str());
|
||||
sCond.type = ctGreater;
|
||||
} else if (startswith(rest.c_str(), "lt(")) {
|
||||
string compVal = rest.substr(4, rest.size() - 5);
|
||||
sCond.compareValue = atoi(compVal.c_str());
|
||||
sCond.type = ctLower;
|
||||
} else if (startswith(rest.c_str(), "eq(")) {
|
||||
string compVal = rest.substr(4, rest.size() - 5);
|
||||
sCond.compareValue = atoi(compVal.c_str());
|
||||
sCond.type = ctEquals;
|
||||
}
|
||||
|
||||
conditions.push_back(sCond);
|
||||
}
|
||||
|
||||
void cConditionalParameter::Debug(void) {
|
||||
dsyslog("skindesigner: Condition %s, Type: %s, cond is %s", value.c_str(), (type == cpAnd)?"and combination":((type == cpOr)?"or combination":"single param") , isTrue?"true":"false");
|
||||
for (vector<sCondition>::iterator it = conditions.begin(); it != conditions.end(); it++) {
|
||||
dsyslog("skindesigner: cond token %s, type: %d, compareValue %d, negated: %d", it->tokenName.c_str(), it->type, it->compareValue, it->isNegated);
|
||||
}
|
||||
}
|
138
libtemplate/parameter.h
Normal file
@ -0,0 +1,138 @@
|
||||
#ifndef __TEMPLATEPARAMETER_H
|
||||
#define __TEMPLATEPARAMETER_H
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <algorithm>
|
||||
#include <math.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
enum eAlign {
|
||||
alLeft,
|
||||
alCenter,
|
||||
alRight,
|
||||
alTop,
|
||||
alBottom
|
||||
};
|
||||
|
||||
enum eScrollMode {
|
||||
smNone,
|
||||
smCarriageReturn,
|
||||
smForthAndBack
|
||||
};
|
||||
|
||||
enum eScrollSpeed {
|
||||
ssNone,
|
||||
ssSlow,
|
||||
ssMedium,
|
||||
ssFast
|
||||
};
|
||||
|
||||
enum eOrientation {
|
||||
orNone,
|
||||
orHorizontal,
|
||||
orVertical,
|
||||
orAbsolute
|
||||
};
|
||||
|
||||
// --- cNumericParameter -------------------------------------------------------------
|
||||
|
||||
class cNumericParameter {
|
||||
private:
|
||||
cGlobals *globals;
|
||||
string value;
|
||||
bool isValid;
|
||||
int width;
|
||||
int height;
|
||||
int columnWidth;
|
||||
int rowHeight;
|
||||
bool hor;
|
||||
int defaultValue;
|
||||
bool IsNumber(const string& s);
|
||||
bool CheckPercentValue(int &val);
|
||||
bool CheckExpression(int &val, string &parsedVal);
|
||||
bool ValidNumericExpression(string &parsedValue);
|
||||
int EvaluateTheExpression(char* expr);
|
||||
double ParseAtom(char*& expr);
|
||||
double ParseFactors(char*& expr);
|
||||
double ParseSummands(char*& expr);
|
||||
public:
|
||||
cNumericParameter(string value);
|
||||
virtual ~cNumericParameter(void);
|
||||
void SetGlobals(cGlobals *globals) { this->globals = globals; };
|
||||
void SetAreaSize(int w, int h);
|
||||
void SetLoopContainer(int columnWidth, int rowHeight) { this->columnWidth = columnWidth; this->rowHeight = rowHeight; };
|
||||
void SetDefault(int def) { defaultValue = def; };
|
||||
void SetHorizontal(void) { hor = true; };
|
||||
void SetVertical(void) { hor = false; };
|
||||
int Parse(string &parsedValue);
|
||||
bool Valid(void) { return isValid; };
|
||||
};
|
||||
|
||||
// --- cTextToken -------------------------------------------------------------
|
||||
|
||||
enum eTextTokenType {
|
||||
ttConstString,
|
||||
ttToken,
|
||||
ttConditionalToken
|
||||
};
|
||||
|
||||
class cTextToken {
|
||||
public:
|
||||
eTextTokenType type;
|
||||
string value;
|
||||
vector<cTextToken> subTokens;
|
||||
};
|
||||
|
||||
// --- cConditionalParameter -------------------------------------------------------------
|
||||
|
||||
enum eCondParameterType {
|
||||
cpAnd,
|
||||
cpOr,
|
||||
cpNone
|
||||
};
|
||||
|
||||
enum eCondType {
|
||||
ctLower,
|
||||
ctGreater,
|
||||
ctEquals,
|
||||
ctBool,
|
||||
ctStringSet,
|
||||
ctNone
|
||||
};
|
||||
|
||||
struct sCondition {
|
||||
string tokenName;
|
||||
bool isNegated;
|
||||
eCondType type;
|
||||
int compareValue;
|
||||
};
|
||||
|
||||
class cConditionalParameter {
|
||||
private:
|
||||
cGlobals *globals;
|
||||
bool isTrue;
|
||||
string value;
|
||||
eCondParameterType type;
|
||||
vector<sCondition> conditions;
|
||||
void TokenizeValue(string sep);
|
||||
void InsertCondition(string cond);
|
||||
int EvaluateParameter(string token, map < string, int > *intTokens, map < string, string > *stringTokens);
|
||||
public:
|
||||
cConditionalParameter(cGlobals *globals, string value);
|
||||
virtual ~cConditionalParameter(void);
|
||||
void Tokenize(void);
|
||||
bool Evaluate(map < string, int > *intTokens, map < string, string > *stringTokens);
|
||||
bool IsTrue(void) { return isTrue; };
|
||||
void Debug(void);
|
||||
};
|
||||
#endif //__TEMPLATEPARAMETER_H
|
273
libtemplate/template.c
Normal file
@ -0,0 +1,273 @@
|
||||
#include "template.h"
|
||||
#include "xmlparser.h"
|
||||
#include "../config.h"
|
||||
|
||||
// --- cTemplate -------------------------------------------------------------
|
||||
|
||||
cTemplate::cTemplate(eViewType viewType) {
|
||||
globals = NULL;
|
||||
rootView = NULL;
|
||||
this->viewType = viewType;
|
||||
CreateView();
|
||||
}
|
||||
|
||||
cTemplate::~cTemplate() {
|
||||
|
||||
if (rootView)
|
||||
delete rootView;
|
||||
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* Public Functions
|
||||
*******************************************************************/
|
||||
bool cTemplate::ReadFromXML(void) {
|
||||
std::string xmlFile;
|
||||
switch (viewType) {
|
||||
case vtDisplayChannel:
|
||||
xmlFile = "displaychannel.xml";
|
||||
break;
|
||||
case vtDisplayMenu:
|
||||
xmlFile = "displaymenu.xml";
|
||||
break;
|
||||
case vtDisplayMessage:
|
||||
xmlFile = "displaymessage.xml";
|
||||
break;
|
||||
case vtDisplayReplay:
|
||||
xmlFile = "displayreplay.xml";
|
||||
break;
|
||||
case vtDisplayVolume:
|
||||
xmlFile = "displayvolume.xml";
|
||||
break;
|
||||
case vtDisplayAudioTracks:
|
||||
xmlFile = "displayaudiotracks.xml";
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
cXmlParser parser;
|
||||
if (!parser.ReadView(rootView, xmlFile)) {
|
||||
return false;
|
||||
}
|
||||
if (!parser.ParseView()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void cTemplate::SetGlobals(cGlobals *globals) {
|
||||
this->globals = globals;
|
||||
rootView->SetGlobals(globals);
|
||||
}
|
||||
|
||||
void cTemplate::Translate(void) {
|
||||
rootView->Translate();
|
||||
}
|
||||
|
||||
|
||||
void cTemplate::PreCache(void) {
|
||||
rootView->PreCache(false);
|
||||
}
|
||||
|
||||
vector< pair<string, int> > cTemplate::GetUsedFonts(void) {
|
||||
vector< pair<string, int> > usedFonts;
|
||||
|
||||
GetUsedFonts(rootView, usedFonts);
|
||||
|
||||
rootView->InitSubViewIterator();
|
||||
cTemplateView *subView = NULL;
|
||||
while(subView = rootView->GetNextSubView()) {
|
||||
GetUsedFonts(subView, usedFonts);
|
||||
}
|
||||
|
||||
return usedFonts;
|
||||
}
|
||||
|
||||
|
||||
void cTemplate::CacheImages(void) {
|
||||
CacheImages(rootView);
|
||||
|
||||
rootView->InitSubViewIterator();
|
||||
cTemplateView *subView = NULL;
|
||||
while(subView = rootView->GetNextSubView()) {
|
||||
CacheImages(subView);
|
||||
}
|
||||
}
|
||||
|
||||
void cTemplate::Debug(void) {
|
||||
|
||||
rootView->Debug();
|
||||
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* Private Functions
|
||||
*******************************************************************/
|
||||
|
||||
void cTemplate::CreateView(void) {
|
||||
switch (viewType) {
|
||||
case vtDisplayChannel:
|
||||
rootView = new cTemplateViewChannel();
|
||||
break;
|
||||
case vtDisplayMenu:
|
||||
rootView = new cTemplateViewMenu();
|
||||
break;
|
||||
case vtDisplayReplay:
|
||||
rootView = new cTemplateViewReplay();
|
||||
break;
|
||||
case vtDisplayVolume:
|
||||
rootView = new cTemplateViewVolume();
|
||||
break;
|
||||
case vtDisplayAudioTracks:
|
||||
rootView = new cTemplateViewAudioTracks();
|
||||
break;
|
||||
case vtDisplayMessage:
|
||||
rootView = new cTemplateViewMessage();
|
||||
break;
|
||||
default:
|
||||
esyslog("skindesigner: unknown view %d", viewType);
|
||||
}
|
||||
}
|
||||
|
||||
void cTemplate::GetUsedFonts(cTemplateView *view, vector< pair<string, int> > &usedFonts) {
|
||||
//used fonts in viewElements
|
||||
view->InitViewElementIterator();
|
||||
cTemplateViewElement *viewElement = NULL;
|
||||
while(viewElement = view->GetNextViewElement()) {
|
||||
viewElement->InitIterator();
|
||||
cTemplatePixmap *pix = NULL;
|
||||
while(pix = viewElement->GetNextPixmap()) {
|
||||
pix->InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
while(func = pix->GetNextFunction()) {
|
||||
if (func->GetType() == ftDrawText) {
|
||||
usedFonts.push_back(pair<string,int>(func->GetFontName(), func->GetNumericParameter(ptFontSize)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//used fonts in viewLists pixmaps
|
||||
view->InitViewListIterator();
|
||||
cTemplateViewList *viewList = NULL;
|
||||
while(viewList = view->GetNextViewList()) {
|
||||
viewList->InitIterator();
|
||||
cTemplatePixmap *pix = NULL;
|
||||
while(pix = viewList->GetNextPixmap()) {
|
||||
pix->InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
while(func = pix->GetNextFunction()) {
|
||||
if (func->GetType() == ftDrawText) {
|
||||
usedFonts.push_back(pair<string,int>(func->GetFontName(), func->GetNumericParameter(ptFontSize)));
|
||||
}
|
||||
}
|
||||
}
|
||||
cTemplateViewElement *listElement = viewList->GetListElement();
|
||||
listElement->InitIterator();
|
||||
while(pix = listElement->GetNextPixmap()) {
|
||||
pix->InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
while(func = pix->GetNextFunction()) {
|
||||
if (func->GetType() == ftDrawText) {
|
||||
usedFonts.push_back(pair<string,int>(func->GetFontName(), func->GetNumericParameter(ptFontSize)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//used fonts in viewTabs
|
||||
view->InitViewTabIterator();
|
||||
cTemplateViewTab *viewTab = NULL;
|
||||
while(viewTab = view->GetNextViewTab()) {
|
||||
viewTab->InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
while(func = viewTab->GetNextFunction()) {
|
||||
if (func->GetType() == ftDrawText) {
|
||||
usedFonts.push_back(pair<string,int>(func->GetFontName(), func->GetNumericParameter(ptFontSize)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cTemplate::CacheImages(cTemplateView *view) {
|
||||
//used images in viewElements
|
||||
view->InitViewElementIterator();
|
||||
cTemplateViewElement *viewElement = NULL;
|
||||
while(viewElement = view->GetNextViewElement()) {
|
||||
viewElement->InitIterator();
|
||||
cTemplatePixmap *pix = NULL;
|
||||
while(pix = viewElement->GetNextPixmap()) {
|
||||
pix->InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
while(func = pix->GetNextFunction()) {
|
||||
if (func->GetType() == ftDrawImage) {
|
||||
CacheImage(func);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//used images in viewLists pixmaps
|
||||
view->InitViewListIterator();
|
||||
cTemplateViewList *viewList = NULL;
|
||||
while(viewList = view->GetNextViewList()) {
|
||||
viewList->InitIterator();
|
||||
cTemplatePixmap *pix = NULL;
|
||||
while(pix = viewList->GetNextPixmap()) {
|
||||
pix->InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
while(func = pix->GetNextFunction()) {
|
||||
if (func->GetType() == ftDrawImage) {
|
||||
CacheImage(func);
|
||||
}
|
||||
}
|
||||
}
|
||||
cTemplateViewElement *listElement = viewList->GetListElement();
|
||||
listElement->InitIterator();
|
||||
while(pix = listElement->GetNextPixmap()) {
|
||||
pix->InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
while(func = pix->GetNextFunction()) {
|
||||
if (func->GetType() == ftDrawImage) {
|
||||
CacheImage(func);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//used logos in viewTabs
|
||||
view->InitViewTabIterator();
|
||||
cTemplateViewTab *viewTab = NULL;
|
||||
while(viewTab = view->GetNextViewTab()) {
|
||||
viewTab->InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
while(func = viewTab->GetNextFunction()) {
|
||||
if (func->GetType() == ftDrawImage) {
|
||||
CacheImage(func);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cTemplate::CacheImage(cTemplateFunction *func) {
|
||||
eImageType imgType = (eImageType)func->GetNumericParameter(ptImageType);
|
||||
int width = func->GetNumericParameter(ptWidth);
|
||||
int height = func->GetNumericParameter(ptHeight);
|
||||
|
||||
switch (imgType) {
|
||||
case itIcon:
|
||||
case itMenuIcon: {
|
||||
string path = func->GetParameter(ptPath);
|
||||
imgCache->CacheIcon(imgType, path, width, height);
|
||||
break; }
|
||||
case itChannelLogo: {
|
||||
string doCache = func->GetParameter(ptCache);
|
||||
if (!doCache.compare("true")) {
|
||||
imgCache->CacheLogo(width, height);
|
||||
}
|
||||
break; }
|
||||
case itSkinPart: {
|
||||
string path = func->GetParameter(ptPath);
|
||||
imgCache->CacheSkinpart(path, width, height);
|
||||
break; }
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
57
libtemplate/template.h
Normal file
@ -0,0 +1,57 @@
|
||||
#ifndef __TEMPLATE_H
|
||||
#define __TEMPLATE_H
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
#include "globals.h"
|
||||
#include "templateview.h"
|
||||
#include "templateviewelement.h"
|
||||
#include "templatepixmap.h"
|
||||
#include "templatefunction.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// --- cTemplate -------------------------------------------------------------
|
||||
enum eViewType {
|
||||
vtDisplayChannel,
|
||||
vtDisplayMenu,
|
||||
vtDisplayReplay,
|
||||
vtDisplayVolume,
|
||||
vtDisplayAudioTracks,
|
||||
vtDisplayMessage
|
||||
};
|
||||
|
||||
class cTemplate {
|
||||
private:
|
||||
eViewType viewType;
|
||||
void CacheImage(cTemplateFunction *func);
|
||||
protected:
|
||||
cGlobals *globals;
|
||||
cTemplateView *rootView;
|
||||
void CreateView(void);
|
||||
void GetUsedFonts(cTemplateView *view, vector< pair<string, int> > &usedFonts);
|
||||
void CacheImages(cTemplateView *view);
|
||||
public:
|
||||
cTemplate(eViewType viewType);
|
||||
virtual ~cTemplate(void);
|
||||
bool ReadFromXML(void);
|
||||
void SetGlobals(cGlobals *globals);
|
||||
cTemplateView *GetRootView(void) { return rootView; };
|
||||
void Translate(void);
|
||||
void PreCache(void);
|
||||
//get fonts for pre caching
|
||||
vector< pair<string, int> > GetUsedFonts(void);
|
||||
void CacheImages(void);
|
||||
//Debug
|
||||
void Debug(void);
|
||||
};
|
||||
|
||||
#endif //__TEMPLATE_H
|
1474
libtemplate/templatefunction.c
Normal file
211
libtemplate/templatefunction.h
Normal file
@ -0,0 +1,211 @@
|
||||
#ifndef __TEMPLATEFUNCTION_H
|
||||
#define __TEMPLATEFUNCTION_H
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
#include "globals.h"
|
||||
#include "parameter.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// --- cTemplateFunction -------------------------------------------------------------
|
||||
|
||||
enum eFuncType {
|
||||
ftOsd,
|
||||
ftView,
|
||||
ftViewElement,
|
||||
ftViewList,
|
||||
ftPixmap,
|
||||
ftPixmapScroll,
|
||||
ftLoop,
|
||||
ftFill,
|
||||
ftDrawText,
|
||||
ftDrawTextBox,
|
||||
ftDrawImage,
|
||||
ftDrawRectangle,
|
||||
ftDrawEllipse,
|
||||
ftNone
|
||||
};
|
||||
|
||||
enum eParamType {
|
||||
ptCond,
|
||||
ptName,
|
||||
ptX,
|
||||
ptY,
|
||||
ptWidth,
|
||||
ptHeight,
|
||||
ptMenuItemWidth,
|
||||
ptFadeTime,
|
||||
ptDelay,
|
||||
ptImageType,
|
||||
ptPath,
|
||||
ptColor,
|
||||
ptFont,
|
||||
ptFontSize,
|
||||
ptText,
|
||||
ptLayer,
|
||||
ptTransparency,
|
||||
ptQuadrant,
|
||||
ptAlign,
|
||||
ptValign,
|
||||
ptScrollMode,
|
||||
ptScrollSpeed,
|
||||
ptOrientation,
|
||||
ptNumElements,
|
||||
ptScrollElement,
|
||||
ptScrollHeight,
|
||||
ptFloat,
|
||||
ptFloatWidth,
|
||||
ptFloatHeight,
|
||||
ptMaxLines,
|
||||
ptColumnWidth,
|
||||
ptRowHeight,
|
||||
ptOverflow,
|
||||
ptScaleTvX,
|
||||
ptScaleTvY,
|
||||
ptScaleTvWidth,
|
||||
ptScaleTvHeight,
|
||||
ptCache,
|
||||
ptDeterminateFont,
|
||||
ptNone
|
||||
};
|
||||
|
||||
enum eImageType {
|
||||
itChannelLogo,
|
||||
itSepLogo,
|
||||
itSkinPart,
|
||||
itMenuIcon,
|
||||
itIcon,
|
||||
itImage
|
||||
};
|
||||
|
||||
enum eFloatType {
|
||||
flNone,
|
||||
flTopLeft,
|
||||
flTopRight
|
||||
};
|
||||
|
||||
enum eOverflowType {
|
||||
otNone,
|
||||
otWrap,
|
||||
otCut
|
||||
};
|
||||
|
||||
class cTemplateFunction {
|
||||
protected:
|
||||
eFuncType type;
|
||||
bool debug;
|
||||
int containerX; //X of parent container
|
||||
int containerY; //Y of parent container
|
||||
int containerWidth; //width of parent container
|
||||
int containerHeight; //height of parent container
|
||||
int columnWidth; //if func is executed in a loop, width of loop column
|
||||
int rowHeight; //if func is executed in a loop, height of loop row
|
||||
cGlobals *globals; //globals
|
||||
map< eParamType, string > nativeParameters; //native parameters directly from xml
|
||||
map< eParamType, int > numericParameters; //sucessfully parsed numeric parameters
|
||||
map< eParamType, string > numericDynamicParameters; //numeric parameters with dynamic tokens
|
||||
bool parsedCompletely;
|
||||
bool updated;
|
||||
map< eParamType, tColor > colorParameters;
|
||||
cConditionalParameter *condParam;
|
||||
//drawimage parameters
|
||||
string imgPath;
|
||||
//drawtext parameters
|
||||
string fontName;
|
||||
vector<cTextToken> textTokens;
|
||||
string parsedText;
|
||||
int parsedTextWidth;
|
||||
string cuttedText;
|
||||
bool alreadyCutted;
|
||||
//drawtextbox parameters
|
||||
int textboxHeight;
|
||||
//dynamic tokens
|
||||
map < string, string > *stringTokens;
|
||||
map < string, int > *intTokens;
|
||||
//private functions
|
||||
bool SetCondition(string cond);
|
||||
bool SetNumericParameter(eParamType type, string value);
|
||||
bool SetAlign(eParamType type, string value);
|
||||
bool SetFont(eParamType type, string value);
|
||||
bool SetImageType(eParamType type, string value);
|
||||
bool SetColor(eParamType type, string value);
|
||||
bool SetTextTokens(string value);
|
||||
void ParseTextToken(string &value, size_t start, size_t end);
|
||||
void ParseConditionalTextToken(string &value, size_t start, size_t end);
|
||||
bool SetScrollMode(string value);
|
||||
bool SetScrollSpeed(string value);
|
||||
bool SetOrientation(string value);
|
||||
bool SetFloating(string value);
|
||||
bool SetOverflow(string value);
|
||||
void ParseStringParameters(void);
|
||||
void ParseNumericalParameters(void);
|
||||
void CalculateAlign(int elementWidth, int elementHeight);
|
||||
int CalculateTextBoxHeight(void);
|
||||
public:
|
||||
cTemplateFunction(eFuncType type);
|
||||
virtual ~cTemplateFunction(void);
|
||||
//Setter Functions
|
||||
void SetParameters(vector<pair<string, string> > params);
|
||||
void SetParameter(eParamType type, string value);
|
||||
void SetContainer(int x, int y, int w, int h);
|
||||
void SetLoopContainer(int columnWidth, int rowHeight);
|
||||
void SetWidthManually(string width);
|
||||
void SetHeightManually(string height);
|
||||
void SetXManually(int newX);
|
||||
void SetYManually(int newY);
|
||||
void SetMaxTextWidth(int maxWidth);
|
||||
void SetTextboxHeight(int boxHeight);
|
||||
void SetGlobals(cGlobals *globals) { this->globals = globals; };
|
||||
void SetTranslatedText(string translation);
|
||||
//PreCache Parameters
|
||||
bool CalculateParameters(void);
|
||||
void CompleteParameters(void);
|
||||
//Set and Unset Dynamic Tokens from view
|
||||
void SetStringTokens(map < string, string > *tok) { stringTokens = tok; };
|
||||
void SetIntTokens(map < string, int > *tok) { intTokens = tok; };
|
||||
void UnsetIntTokens(void) { intTokens = NULL; };
|
||||
void UnsetStringTokens(void) { stringTokens = NULL; };
|
||||
//Clear dynamically parameters
|
||||
void ClearDynamicParameters(void);
|
||||
//Parse parameters with dynamically set Tokens
|
||||
bool ParseParameters(void);
|
||||
//Getter Functions
|
||||
eFuncType GetType(void) { return type; };
|
||||
bool DoDebug(void) { return debug; };
|
||||
string GetParameter(eParamType type);
|
||||
int GetNumericParameter(eParamType type);
|
||||
string GetText(bool cut = true);
|
||||
string GetImagePath(void) { return imgPath; };
|
||||
tColor GetColorParameter(eParamType type);
|
||||
string GetFontName(void) { return fontName; };
|
||||
string GetFuncName(void);
|
||||
string GetParamName(eParamType pt);
|
||||
//Dynamic width or height parameter
|
||||
int GetWidth(bool cutted = true);
|
||||
int GetHeight(void);
|
||||
void GetNeededWidths(multimap<eParamType,string> *widths);
|
||||
void GetNeededHeights(multimap<eParamType,string> *heights);
|
||||
void GetNeededPosX(multimap<eParamType,string> *posXs);
|
||||
void GetNeededPosY(multimap<eParamType,string> *posYs);
|
||||
void SetWidth(eParamType type, string label, int funcWidth);
|
||||
void SetHeight(eParamType type, string label, int funcHeight);
|
||||
void SetX(eParamType type, string label, int funcX);
|
||||
void SetY(eParamType type, string label, int funcY);
|
||||
//Status Functions
|
||||
bool ParsedCompletely(void) { return parsedCompletely; };
|
||||
bool DoExecute(void);
|
||||
bool Updated(void) { return updated; };
|
||||
//Debug
|
||||
void Debug(void);
|
||||
};
|
||||
|
||||
#endif //__TEMPLATEFUNCTION_H
|
208
libtemplate/templateloopfunction.c
Normal file
@ -0,0 +1,208 @@
|
||||
#include "templateloopfunction.h"
|
||||
#include "../libcore/helpers.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// --- cTemplateFunction -------------------------------------------------------------
|
||||
|
||||
cTemplateLoopFunction::cTemplateLoopFunction(void) : cTemplateFunction(ftLoop) {
|
||||
}
|
||||
|
||||
cTemplateLoopFunction::~cTemplateLoopFunction(void) {
|
||||
}
|
||||
|
||||
void cTemplateLoopFunction::InitIterator(void) {
|
||||
funcIt = functions.begin();
|
||||
}
|
||||
|
||||
void cTemplateLoopFunction::AddFunction(string name, vector<pair<string, string> > ¶ms) {
|
||||
eFuncType type = ftNone;
|
||||
|
||||
if (!name.compare("drawtext")) {
|
||||
type = ftDrawText;
|
||||
} else if (!name.compare("drawtextbox")) {
|
||||
type = ftDrawTextBox;
|
||||
} else if (!name.compare("drawimage")) {
|
||||
type = ftDrawImage;
|
||||
} else if (!name.compare("drawrectangle")) {
|
||||
type = ftDrawRectangle;
|
||||
} else if (!name.compare("drawellipse")) {
|
||||
type = ftDrawEllipse;
|
||||
}
|
||||
|
||||
if (type == ftNone) {
|
||||
return;
|
||||
}
|
||||
|
||||
cTemplateFunction *f = new cTemplateFunction(type);
|
||||
f->SetParameters(params);
|
||||
functions.push_back(f);
|
||||
}
|
||||
|
||||
void cTemplateLoopFunction::CalculateLoopFuncParameters(void) {
|
||||
int columnWidth = GetNumericParameter(ptColumnWidth);
|
||||
int rowHeight = GetNumericParameter(ptRowHeight);
|
||||
for (vector<cTemplateFunction*>::iterator func = functions.begin(); func != functions.end(); func++) {
|
||||
(*func)->SetGlobals(globals);
|
||||
(*func)->SetContainer(0, 0, containerWidth, containerHeight);
|
||||
(*func)->SetLoopContainer(columnWidth, rowHeight);
|
||||
(*func)->CalculateParameters();
|
||||
(*func)->CompleteParameters();
|
||||
}
|
||||
}
|
||||
|
||||
cTemplateFunction *cTemplateLoopFunction::GetNextFunction(void) {
|
||||
if (funcIt == functions.end())
|
||||
return NULL;
|
||||
cTemplateFunction *func = *funcIt;
|
||||
funcIt++;
|
||||
return func;
|
||||
}
|
||||
|
||||
void cTemplateLoopFunction::ClearDynamicParameters(void) {
|
||||
InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
while(func = GetNextFunction()) {
|
||||
func->ClearDynamicParameters();
|
||||
}
|
||||
}
|
||||
|
||||
void cTemplateLoopFunction::ParseDynamicParameters(map <string,string> *tokens) {
|
||||
if (!tokens)
|
||||
return;
|
||||
InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
|
||||
map <string,int> intTokens;
|
||||
for (map <string,string>::iterator it = tokens->begin(); it != tokens->end(); it++) {
|
||||
if (isNumber(it->second))
|
||||
intTokens.insert(pair<string, int>(it->first, atoi((it->second).c_str())));
|
||||
}
|
||||
|
||||
bool completelyParsed = true;
|
||||
while(func = GetNextFunction()) {
|
||||
func->SetStringTokens(tokens);
|
||||
func->SetIntTokens(&intTokens);
|
||||
bool funcCompletelyParsed = func->ParseParameters();
|
||||
if (!funcCompletelyParsed)
|
||||
completelyParsed = false;
|
||||
if (func->Updated())
|
||||
func->CompleteParameters();
|
||||
func->UnsetStringTokens();
|
||||
func->UnsetIntTokens();
|
||||
}
|
||||
if (completelyParsed) {
|
||||
return;
|
||||
}
|
||||
|
||||
ReplaceWidthFunctions();
|
||||
ReplaceHeightFunctions();
|
||||
}
|
||||
|
||||
int cTemplateLoopFunction::GetLoopElementsWidth(void) {
|
||||
int cW = GetNumericParameter(ptColumnWidth);
|
||||
if (cW > 0) {
|
||||
return cW;
|
||||
}
|
||||
InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
int maxWidth = 1;
|
||||
while(func = GetNextFunction()) {
|
||||
int funcWidth = func->GetWidth(true);
|
||||
if (funcWidth > maxWidth)
|
||||
maxWidth = funcWidth;
|
||||
}
|
||||
return maxWidth;
|
||||
}
|
||||
|
||||
int cTemplateLoopFunction::GetLoopElementsHeight(void) {
|
||||
int rH = GetNumericParameter(ptRowHeight);
|
||||
if (rH > 0)
|
||||
return rH;
|
||||
InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
int maxHeight = 1;
|
||||
while(func = GetNextFunction()) {
|
||||
int funcY = func->GetNumericParameter(ptY);
|
||||
int funcHeight = func->GetHeight();
|
||||
int totalHeight = funcY + funcHeight;
|
||||
if (totalHeight > maxHeight)
|
||||
maxHeight = totalHeight;
|
||||
}
|
||||
return maxHeight;
|
||||
}
|
||||
|
||||
void cTemplateLoopFunction::ReplaceWidthFunctions(void) {
|
||||
InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
while(func = GetNextFunction()) {
|
||||
if (func->ParsedCompletely()) {
|
||||
continue;
|
||||
}
|
||||
multimap<eParamType,string> widths;
|
||||
func->GetNeededWidths(&widths);
|
||||
for (map<eParamType, string>::iterator names = widths.begin(); names !=widths.end(); names++) {
|
||||
eParamType type = names->first;
|
||||
string label = names->second;
|
||||
int funcWidth = 0;
|
||||
for (vector<cTemplateFunction*>::iterator it = functions.begin(); it != functions.end(); it++) {
|
||||
cTemplateFunction *myFunc = *it;
|
||||
string myFuncName = myFunc->GetParameter(ptName);
|
||||
if (!myFuncName.compare(label)) {
|
||||
funcWidth = myFunc->GetWidth();
|
||||
func->SetWidth(type, label, funcWidth);
|
||||
if (func->Updated()) {
|
||||
func->CompleteParameters();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cTemplateLoopFunction::ReplaceHeightFunctions(void) {
|
||||
InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
while(func = GetNextFunction()) {
|
||||
if (func->ParsedCompletely()) {
|
||||
continue;
|
||||
}
|
||||
multimap<eParamType,string> heights;
|
||||
func->GetNeededHeights(&heights);
|
||||
for (map<eParamType, string>::iterator names = heights.begin(); names !=heights.end(); names++) {
|
||||
eParamType type = names->first;
|
||||
string label = names->second;
|
||||
int funcHeight = 0;
|
||||
for (vector<cTemplateFunction*>::iterator it = functions.begin(); it != functions.end(); it++) {
|
||||
cTemplateFunction *myFunc = *it;
|
||||
string myFuncName = myFunc->GetParameter(ptName);
|
||||
if (!myFuncName.compare(label)) {
|
||||
funcHeight = myFunc->GetHeight();
|
||||
func->SetHeight(type, label, funcHeight);
|
||||
if (func->Updated()) {
|
||||
func->CompleteParameters();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool cTemplateLoopFunction::Ready(void) {
|
||||
bool isReady = true;
|
||||
map< eParamType, string >::iterator hit = numericDynamicParameters.find(ptColumnWidth);
|
||||
if (hit != numericDynamicParameters.end())
|
||||
isReady = false;
|
||||
hit = numericDynamicParameters.find(ptRowHeight);
|
||||
if (hit != numericDynamicParameters.end())
|
||||
isReady = false;
|
||||
return isReady;
|
||||
}
|
||||
|
||||
void cTemplateLoopFunction::Debug(void) {
|
||||
cTemplateFunction::Debug();
|
||||
esyslog("skindesigner: functions to be looped:");
|
||||
for (vector<cTemplateFunction*>::iterator func = functions.begin(); func != functions.end(); func++) {
|
||||
(*func)->Debug();
|
||||
}
|
||||
}
|
33
libtemplate/templateloopfunction.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef __TEMPLATELOOPFUNCTION_H
|
||||
#define __TEMPLATELOOPFUNCTION_H
|
||||
|
||||
#include "templatefunction.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// --- cTemplateLoopFunction -------------------------------------------------------------
|
||||
|
||||
class cTemplateLoopFunction : public cTemplateFunction {
|
||||
private:
|
||||
vector<cTemplateFunction*> functions;
|
||||
vector<cTemplateFunction*>::iterator funcIt;
|
||||
void ReplaceWidthFunctions(void);
|
||||
void ReplaceHeightFunctions(void);
|
||||
public:
|
||||
cTemplateLoopFunction(void);
|
||||
virtual ~cTemplateLoopFunction(void);
|
||||
void AddFunction(string name, vector<pair<string, string> > ¶ms);
|
||||
void CalculateLoopFuncParameters(void);
|
||||
void InitIterator(void);
|
||||
cTemplateFunction *GetNextFunction(void);
|
||||
void ClearDynamicParameters(void);
|
||||
void ParseDynamicParameters(map <string,string> *tokens);
|
||||
int GetLoopElementsWidth(void);
|
||||
int GetLoopElementsHeight(void);
|
||||
int GetContainerWidth(void) { return containerWidth; };
|
||||
int GetContainerHeight(void) { return containerHeight; };
|
||||
bool Ready(void);
|
||||
void Debug(void);
|
||||
};
|
||||
|
||||
#endif //__TEMPLATELOOPFUNCTION_H
|
473
libtemplate/templatepixmap.c
Normal file
@ -0,0 +1,473 @@
|
||||
#include "templatepixmap.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// --- cTemplatePixmap -------------------------------------------------------------
|
||||
|
||||
cTemplatePixmap::cTemplatePixmap(void) {
|
||||
parameters = NULL;
|
||||
containerX = 0;
|
||||
containerY = 0;
|
||||
containerWidth = 0;
|
||||
containerHeight = 0;
|
||||
globals = NULL;
|
||||
scrolling = false;
|
||||
}
|
||||
|
||||
cTemplatePixmap::~cTemplatePixmap() {
|
||||
for (vector<cTemplateFunction*>::iterator it = functions.begin(); it != functions.end(); it++) {
|
||||
delete (*it);
|
||||
}
|
||||
if (parameters)
|
||||
delete parameters;
|
||||
}
|
||||
|
||||
void cTemplatePixmap::SetParameters(vector<pair<string, string> > ¶ms) {
|
||||
parameters = new cTemplateFunction(ftPixmap);
|
||||
parameters->SetGlobals(globals);
|
||||
parameters->SetParameters(params);
|
||||
}
|
||||
|
||||
void cTemplatePixmap::SetContainer(int x, int y, int w, int h) {
|
||||
containerX = x;
|
||||
containerY = y;
|
||||
containerWidth = w;
|
||||
containerHeight = h;
|
||||
}
|
||||
|
||||
void cTemplatePixmap::SetWidth(int width) {
|
||||
cString pWidth = cString::sprintf("%d", width);
|
||||
parameters->SetWidthManually(*pWidth);
|
||||
}
|
||||
|
||||
void cTemplatePixmap::SetHeight(int height) {
|
||||
cString pHeight = cString::sprintf("%d", height);
|
||||
parameters->SetHeightManually(*pHeight);
|
||||
}
|
||||
|
||||
void cTemplatePixmap::SetX(int x) {
|
||||
parameters->SetXManually(x);
|
||||
}
|
||||
|
||||
void cTemplatePixmap::SetY(int y) {
|
||||
parameters->SetYManually(y);
|
||||
}
|
||||
|
||||
void cTemplatePixmap::ClearDynamicParameters(void) {
|
||||
parameters->ClearDynamicParameters();
|
||||
}
|
||||
|
||||
void cTemplatePixmap::ParseDynamicParameters(map <string,int> *intTokens, bool initFuncs) {
|
||||
parameters->ClearDynamicParameters();
|
||||
parameters->SetIntTokens(intTokens);
|
||||
parameters->ParseParameters();
|
||||
parameters->UnsetIntTokens();
|
||||
|
||||
if (!DoExecute()) {
|
||||
parameters->ClearDynamicParameters();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!initFuncs || !Ready())
|
||||
return;
|
||||
|
||||
int x = parameters->GetNumericParameter(ptX);
|
||||
int y = parameters->GetNumericParameter(ptY);
|
||||
int width = parameters->GetNumericParameter(ptWidth);
|
||||
int height = parameters->GetNumericParameter(ptHeight);
|
||||
|
||||
for (vector<cTemplateFunction*>::iterator func = functions.begin(); func != functions.end(); func++) {
|
||||
(*func)->SetContainer(x, y, width, height);
|
||||
(*func)->CalculateParameters();
|
||||
(*func)->CompleteParameters();
|
||||
if ((*func)->GetType() == ftLoop) {
|
||||
cTemplateLoopFunction *loopFunc = dynamic_cast<cTemplateLoopFunction*>(*func);
|
||||
if (!loopFunc->Ready()) {
|
||||
loopFunc->SetIntTokens(intTokens);
|
||||
loopFunc->ParseParameters();
|
||||
loopFunc->UnsetIntTokens();
|
||||
}
|
||||
loopFunc->CalculateLoopFuncParameters();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cTemplatePixmap::AddFunction(string name, vector<pair<string, string> > ¶ms) {
|
||||
eFuncType type = ftNone;
|
||||
|
||||
if (!name.compare("fill")) {
|
||||
type = ftFill;
|
||||
} else if (!name.compare("drawtext")) {
|
||||
type = ftDrawText;
|
||||
} else if (!name.compare("drawtextbox")) {
|
||||
type = ftDrawTextBox;
|
||||
} else if (!name.compare("drawimage")) {
|
||||
type = ftDrawImage;
|
||||
} else if (!name.compare("drawrectangle")) {
|
||||
type = ftDrawRectangle;
|
||||
} else if (!name.compare("drawellipse")) {
|
||||
type = ftDrawEllipse;
|
||||
}
|
||||
|
||||
if (type == ftNone) {
|
||||
return;
|
||||
}
|
||||
|
||||
cTemplateFunction *f = new cTemplateFunction(type);
|
||||
f->SetParameters(params);
|
||||
functions.push_back(f);
|
||||
}
|
||||
|
||||
void cTemplatePixmap::AddLoopFunction(cTemplateLoopFunction *lf) {
|
||||
functions.push_back(lf);
|
||||
}
|
||||
|
||||
|
||||
bool cTemplatePixmap::CalculateParameters(void) {
|
||||
bool paramsValid = true;
|
||||
//Calculate Pixmap Size
|
||||
parameters->SetContainer(containerX, containerY, containerWidth, containerHeight);
|
||||
parameters->SetGlobals(globals);
|
||||
paramsValid = parameters->CalculateParameters();
|
||||
|
||||
int pixWidth = parameters->GetNumericParameter(ptWidth);
|
||||
int pixHeight = parameters->GetNumericParameter(ptHeight);
|
||||
|
||||
for (vector<cTemplateFunction*>::iterator func = functions.begin(); func != functions.end(); func++) {
|
||||
(*func)->SetGlobals(globals);
|
||||
if (!Ready())
|
||||
continue;
|
||||
(*func)->SetContainer(0, 0, pixWidth, pixHeight);
|
||||
paramsValid = (*func)->CalculateParameters();
|
||||
(*func)->CompleteParameters();
|
||||
if ((*func)->GetType() == ftLoop) {
|
||||
cTemplateLoopFunction *loopFunc = dynamic_cast<cTemplateLoopFunction*>(*func);
|
||||
loopFunc->CalculateLoopFuncParameters();
|
||||
}
|
||||
}
|
||||
|
||||
return paramsValid;
|
||||
}
|
||||
|
||||
void cTemplatePixmap::ClearDynamicFunctionParameters(void) {
|
||||
InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
while(func = GetNextFunction()) {
|
||||
func->ClearDynamicParameters();
|
||||
}
|
||||
}
|
||||
|
||||
void cTemplatePixmap::ParseDynamicFunctionParameters(map <string,string> *stringTokens, map <string,int> *intTokens) {
|
||||
InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
bool completelyParsed = true;
|
||||
bool updated = false;
|
||||
while(func = GetNextFunction()) {
|
||||
func->SetStringTokens(stringTokens);
|
||||
func->SetIntTokens(intTokens);
|
||||
bool funcCompletelyParsed = func->ParseParameters();
|
||||
if (!funcCompletelyParsed)
|
||||
completelyParsed = false;
|
||||
if (func->Updated())
|
||||
func->CompleteParameters();
|
||||
func->UnsetIntTokens();
|
||||
func->UnsetStringTokens();
|
||||
}
|
||||
|
||||
if (completelyParsed) {
|
||||
return;
|
||||
}
|
||||
|
||||
ReplaceWidthFunctions();
|
||||
ReplaceHeightFunctions();
|
||||
ReplacePosXFunctions();
|
||||
ReplacePosYFunctions();
|
||||
}
|
||||
|
||||
bool cTemplatePixmap::CalculateDrawPortSize(cSize &size, map < string, vector< map< string, string > > > *loopTokens) {
|
||||
int pixWidth = parameters->GetNumericParameter(ptWidth);
|
||||
int pixHeight = parameters->GetNumericParameter(ptHeight);
|
||||
int orientation = parameters->GetNumericParameter(ptOrientation);
|
||||
if (orientation < 0)
|
||||
orientation = orVertical;
|
||||
if (orientation == orHorizontal) {
|
||||
//get function which determinates drawport width
|
||||
cTemplateFunction *scrollFunc = GetScrollFunction();
|
||||
if (!scrollFunc)
|
||||
return false;
|
||||
int drawportWidth = scrollFunc->GetWidth(false) + scrollFunc->GetNumericParameter(ptX) + 10;
|
||||
if (drawportWidth > pixWidth) {
|
||||
size.SetWidth(drawportWidth);
|
||||
size.SetHeight(pixHeight);
|
||||
return true;
|
||||
}
|
||||
} else if (orientation == orVertical) {
|
||||
//check "last" element height
|
||||
InitIterator();
|
||||
cTemplateFunction *f = NULL;
|
||||
int drawportHeight = 1;
|
||||
while (f = GetNextFunction()) {
|
||||
if (f->GetType() == ftLoop) {
|
||||
cTemplateLoopFunction *loopFunc = dynamic_cast<cTemplateLoopFunction*>(f);
|
||||
//get number of loop tokens
|
||||
string loopTokenName = loopFunc->GetParameter(ptName);
|
||||
int numLoopTokens = 0;
|
||||
map < string, vector< map< string, string > > >::iterator hit = loopTokens->find(loopTokenName);
|
||||
if (hit != loopTokens->end()) {
|
||||
vector< map<string,string> > loopToken = hit->second;
|
||||
numLoopTokens = loopToken.size();
|
||||
//parse first loop token element to get correct height
|
||||
vector< map<string,string> >::iterator firstLoopToken = loopToken.begin();
|
||||
loopFunc->ClearDynamicParameters();
|
||||
loopFunc->ParseDynamicParameters(&(*firstLoopToken));
|
||||
}
|
||||
int orientation = loopFunc->GetNumericParameter(ptOrientation);
|
||||
int yFunc = loopFunc->GetNumericParameter(ptY);
|
||||
int heightFunc = loopFunc->GetLoopElementsHeight();
|
||||
if (loopTokens && orientation == orVertical) {
|
||||
//height is height of loop elements times num loop elements
|
||||
heightFunc = heightFunc * numLoopTokens;
|
||||
} else if (loopTokens && orientation == orHorizontal) {
|
||||
int overflow = loopFunc->GetNumericParameter(ptOverflow);
|
||||
if (overflow == otCut) {
|
||||
//do nothing, height is only height of one line
|
||||
} else if (overflow == otWrap) {
|
||||
int widthFunc = loopFunc->GetLoopElementsWidth();
|
||||
if (widthFunc <= 0)
|
||||
continue;
|
||||
int loopWidth = loopFunc->GetNumericParameter(ptWidth);
|
||||
if (loopWidth <= 0)
|
||||
loopWidth = loopFunc->GetContainerWidth();
|
||||
int elementsPerRow = loopWidth / widthFunc;
|
||||
int rest = loopWidth % widthFunc;
|
||||
if (rest > 0)
|
||||
elementsPerRow++;
|
||||
if (elementsPerRow <= 0)
|
||||
continue;
|
||||
int lines = numLoopTokens / elementsPerRow;
|
||||
rest = numLoopTokens % elementsPerRow;
|
||||
if (rest > 0)
|
||||
lines++;
|
||||
heightFunc = heightFunc * lines;
|
||||
}
|
||||
}
|
||||
int neededHeight = heightFunc + yFunc;
|
||||
if (neededHeight > drawportHeight)
|
||||
drawportHeight = neededHeight;
|
||||
} else {
|
||||
int yFunc = f->GetNumericParameter(ptY);
|
||||
int heightFunc = f->GetHeight();
|
||||
int neededHeight = heightFunc + yFunc;
|
||||
if (neededHeight > drawportHeight)
|
||||
drawportHeight = neededHeight;
|
||||
}
|
||||
}
|
||||
if (drawportHeight > pixHeight) {
|
||||
size.SetWidth(pixWidth);
|
||||
size.SetHeight(drawportHeight);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
size.SetWidth(0);
|
||||
size.SetHeight(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
void cTemplatePixmap::SetScrollingTextWidth(void) {
|
||||
int orientation = parameters->GetNumericParameter(ptOrientation);
|
||||
if (orientation != orHorizontal)
|
||||
return;
|
||||
int pixWidth = parameters->GetNumericParameter(ptWidth);
|
||||
InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
while(func = GetNextFunction()) {
|
||||
if (func->GetType() == ftDrawText) {
|
||||
int offset = func->GetNumericParameter(ptX);
|
||||
func->SetMaxTextWidth(pixWidth - offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cTemplateFunction *cTemplatePixmap::GetScrollFunction(void) {
|
||||
string scrollElement = parameters->GetParameter(ptScrollElement);
|
||||
if (scrollElement.size() == 0)
|
||||
return NULL;
|
||||
InitIterator();
|
||||
cTemplateFunction *f = NULL;
|
||||
bool foundElement = false;
|
||||
while (f = GetNextFunction()) {
|
||||
string funcName = f->GetParameter(ptName);
|
||||
if (!funcName.compare(scrollElement)) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cRect cTemplatePixmap::GetPixmapSize(void) {
|
||||
cRect size;
|
||||
size.SetX(GetNumericParameter(ptX));
|
||||
size.SetY(GetNumericParameter(ptY));
|
||||
size.SetWidth(GetNumericParameter(ptWidth));
|
||||
size.SetHeight(GetNumericParameter(ptHeight));
|
||||
return size;
|
||||
}
|
||||
|
||||
int cTemplatePixmap::GetNumericParameter(eParamType type) {
|
||||
if (!parameters)
|
||||
return -1;
|
||||
return parameters->GetNumericParameter(type);
|
||||
}
|
||||
|
||||
void cTemplatePixmap::InitIterator(void) {
|
||||
funcIt = functions.begin();
|
||||
}
|
||||
|
||||
cTemplateFunction *cTemplatePixmap::GetNextFunction(void) {
|
||||
if (funcIt == functions.end())
|
||||
return NULL;
|
||||
cTemplateFunction *func = *funcIt;
|
||||
funcIt++;
|
||||
return func;
|
||||
}
|
||||
|
||||
bool cTemplatePixmap::Ready(void) {
|
||||
int myX = parameters->GetNumericParameter(ptX);
|
||||
if (myX < 0)
|
||||
return false;
|
||||
int myY = parameters->GetNumericParameter(ptY);
|
||||
if (myY < 0)
|
||||
return false;
|
||||
int myWidth = parameters->GetNumericParameter(ptWidth);
|
||||
if (myWidth < 1)
|
||||
return false;
|
||||
int myHeight = parameters->GetNumericParameter(ptHeight);
|
||||
if (myHeight < 1)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void cTemplatePixmap::ReplaceWidthFunctions(void) {
|
||||
InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
while(func = GetNextFunction()) {
|
||||
if (func->ParsedCompletely()) {
|
||||
continue;
|
||||
}
|
||||
multimap<eParamType,string> widths;
|
||||
func->GetNeededWidths(&widths);
|
||||
for (map<eParamType, string>::iterator names = widths.begin(); names !=widths.end(); names++) {
|
||||
eParamType type = names->first;
|
||||
string label = names->second;
|
||||
int funcWidth = 0;
|
||||
for (vector<cTemplateFunction*>::iterator it = functions.begin(); it != functions.end(); it++) {
|
||||
cTemplateFunction *myFunc = *it;
|
||||
string myFuncName = myFunc->GetParameter(ptName);
|
||||
if (!myFuncName.compare(label)) {
|
||||
funcWidth = myFunc->GetWidth();
|
||||
func->SetWidth(type, label, funcWidth);
|
||||
if (func->Updated()) {
|
||||
func->CompleteParameters();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cTemplatePixmap::ReplaceHeightFunctions(void) {
|
||||
InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
while(func = GetNextFunction()) {
|
||||
if (func->ParsedCompletely()) {
|
||||
continue;
|
||||
}
|
||||
multimap<eParamType,string> heights;
|
||||
func->GetNeededHeights(&heights);
|
||||
for (map<eParamType, string>::iterator names = heights.begin(); names !=heights.end(); names++) {
|
||||
eParamType type = names->first;
|
||||
string label = names->second;
|
||||
int funcHeight = 0;
|
||||
for (vector<cTemplateFunction*>::iterator it = functions.begin(); it != functions.end(); it++) {
|
||||
cTemplateFunction *myFunc = *it;
|
||||
string myFuncName = myFunc->GetParameter(ptName);
|
||||
if (!myFuncName.compare(label)) {
|
||||
funcHeight = myFunc->GetHeight();
|
||||
func->SetHeight(type, label, funcHeight);
|
||||
if (func->Updated()) {
|
||||
func->CompleteParameters();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cTemplatePixmap::ReplacePosXFunctions(void) {
|
||||
InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
while(func = GetNextFunction()) {
|
||||
if (func->ParsedCompletely()) {
|
||||
continue;
|
||||
}
|
||||
multimap<eParamType,string> posXs;
|
||||
func->GetNeededPosX(&posXs);
|
||||
for (map<eParamType, string>::iterator names = posXs.begin(); names !=posXs.end(); names++) {
|
||||
eParamType type = names->first;
|
||||
string label = names->second;
|
||||
int funcX = 0;
|
||||
for (vector<cTemplateFunction*>::iterator it = functions.begin(); it != functions.end(); it++) {
|
||||
cTemplateFunction *myFunc = *it;
|
||||
string myFuncName = myFunc->GetParameter(ptName);
|
||||
if (!myFuncName.compare(label)) {
|
||||
funcX = myFunc->GetNumericParameter(ptX);
|
||||
if (funcX > -1) {
|
||||
func->SetX(type, label, funcX);
|
||||
if (func->Updated()) {
|
||||
func->CompleteParameters();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cTemplatePixmap::ReplacePosYFunctions(void) {
|
||||
InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
while(func = GetNextFunction()) {
|
||||
if (func->ParsedCompletely()) {
|
||||
continue;
|
||||
}
|
||||
multimap<eParamType,string> posYs;
|
||||
func->GetNeededPosY(&posYs);
|
||||
for (map<eParamType, string>::iterator names = posYs.begin(); names !=posYs.end(); names++) {
|
||||
eParamType type = names->first;
|
||||
string label = names->second;
|
||||
int funcY = 0;
|
||||
for (vector<cTemplateFunction*>::iterator it = functions.begin(); it != functions.end(); it++) {
|
||||
cTemplateFunction *myFunc = *it;
|
||||
string myFuncName = myFunc->GetParameter(ptName);
|
||||
if (!myFuncName.compare(label)) {
|
||||
funcY = myFunc->GetNumericParameter(ptY);
|
||||
if (funcY > -1) {
|
||||
func->SetY(type, label, funcY);
|
||||
if (func->Updated()) {
|
||||
func->CompleteParameters();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cTemplatePixmap::Debug(void) {
|
||||
esyslog("skindesigner: pixmap container size x: %d, y: %d, width: %d, height %d", containerX, containerY, containerWidth, containerHeight);
|
||||
parameters->Debug();
|
||||
for (vector<cTemplateFunction*>::iterator it = functions.begin(); it != functions.end(); it++) {
|
||||
(*it)->Debug();
|
||||
}
|
||||
}
|
82
libtemplate/templatepixmap.h
Normal file
@ -0,0 +1,82 @@
|
||||
#ifndef __TEMPLATEPIXMAP_H
|
||||
#define __TEMPLATEPIXMAP_H
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
#include "globals.h"
|
||||
#include "templateloopfunction.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// --- cTemplatePixmap -------------------------------------------------------------
|
||||
|
||||
class cTemplatePixmap {
|
||||
protected:
|
||||
bool scrolling;
|
||||
cTemplateFunction *parameters;
|
||||
vector<cTemplateFunction*> functions;
|
||||
vector<cTemplateFunction*>::iterator funcIt;
|
||||
int containerX;
|
||||
int containerY;
|
||||
int containerWidth;
|
||||
int containerHeight;
|
||||
cGlobals *globals;
|
||||
//functions replacing {width(label)} and {height(label)} tokens
|
||||
void ReplaceWidthFunctions(void);
|
||||
void ReplaceHeightFunctions(void);
|
||||
//functions replacing {posx(label)} and {posy(label)} tokens
|
||||
void ReplacePosXFunctions(void);
|
||||
void ReplacePosYFunctions(void);
|
||||
//Get Scrolling Function
|
||||
cTemplateFunction *GetScrollFunction(void);
|
||||
public:
|
||||
cTemplatePixmap(void);
|
||||
virtual ~cTemplatePixmap(void);
|
||||
//Setter Functions
|
||||
void SetScrolling(void) { scrolling = true; };
|
||||
void SetParameters(vector<pair<string, string> > ¶ms);
|
||||
void SetWidth(int width);
|
||||
void SetHeight(int height);
|
||||
void SetX(int x);
|
||||
void SetY(int y);
|
||||
void SetContainer(int x, int y, int w, int h);
|
||||
void SetGlobals(cGlobals *globals) { this->globals = globals; };
|
||||
void AddFunction(string name, vector<pair<string, string> > ¶ms);
|
||||
void AddLoopFunction(cTemplateLoopFunction *lf);
|
||||
//PreCache Parameters
|
||||
bool CalculateParameters(void);
|
||||
//clear dynamically set function parameters
|
||||
void ClearDynamicFunctionParameters(void);
|
||||
//Clear dynamically set pixmap parameters
|
||||
void ClearDynamicParameters(void);
|
||||
//Parse pixmap parameters with dynamically set Tokens
|
||||
void ParseDynamicParameters(map <string,int> *intTokens, bool initFuncs);
|
||||
//Parse all function parameters with dynamically set Tokens
|
||||
void ParseDynamicFunctionParameters(map <string,string> *stringTokens, map <string,int> *intTokens);
|
||||
//Calculate size of drawport in case area scrolls
|
||||
bool CalculateDrawPortSize(cSize &size, map < string, vector< map< string, string > > > *loopTokens = NULL);
|
||||
//Set max width for text in scrollarea
|
||||
void SetScrollingTextWidth(void);
|
||||
//Getter Functions
|
||||
cRect GetPixmapSize(void);
|
||||
int GetNumericParameter(eParamType type);
|
||||
bool Scrolling(void) { return scrolling; };
|
||||
bool DoExecute(void) { return parameters->DoExecute(); };
|
||||
bool DoDebug(void) { return parameters->DoDebug(); };
|
||||
bool Ready(void);
|
||||
//Traverse Functions
|
||||
void InitIterator(void);
|
||||
cTemplateFunction *GetNextFunction(void);
|
||||
//Debug
|
||||
void Debug(void);
|
||||
};
|
||||
|
||||
#endif //__TEMPLATEPIXMAP_H
|
1567
libtemplate/templateview.c
Normal file
198
libtemplate/templateview.h
Normal file
@ -0,0 +1,198 @@
|
||||
#ifndef __TEMPLATEVIEW_H
|
||||
#define __TEMPLATEVIEW_H
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
#include "templateviewelement.h"
|
||||
#include "templateviewlist.h"
|
||||
#include "templatepixmap.h"
|
||||
#include "templateviewtab.h"
|
||||
#include "templatefunction.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// --- cTemplateView -------------------------------------------------------------
|
||||
|
||||
enum eSubView {
|
||||
svUndefined,
|
||||
svMenuDefault,
|
||||
svMenuMain,
|
||||
svMenuSetup,
|
||||
svMenuSchedules,
|
||||
svMenuTimers,
|
||||
svMenuRecordings,
|
||||
svMenuChannels,
|
||||
svMenuDetailedEpg,
|
||||
svMenuDetailedRecording,
|
||||
svMenuDetailedText
|
||||
};
|
||||
|
||||
class cTemplateView {
|
||||
private:
|
||||
protected:
|
||||
cGlobals *globals;
|
||||
//view parameters
|
||||
string viewName;
|
||||
cTemplateFunction *parameters;
|
||||
int containerX;
|
||||
int containerY;
|
||||
int containerWidth;
|
||||
int containerHeight;
|
||||
//basic view data structures
|
||||
map < eViewElement, cTemplateViewElement* > viewElements;
|
||||
map < eViewList, cTemplateViewList* > viewLists;
|
||||
map < eSubView, cTemplateView* > subViews;
|
||||
vector< cTemplateViewTab* > viewTabs;
|
||||
//helpers to iterate data structures
|
||||
map < eViewElement, cTemplateViewElement* >::iterator veIt;
|
||||
map < eViewList, cTemplateViewList* >::iterator vlIt;
|
||||
map < eSubView, cTemplateView* >::iterator svIt;
|
||||
vector< cTemplateViewTab* >::iterator vtIt;
|
||||
//helpers to check valid xml templates
|
||||
set<string> subViewsAllowed;
|
||||
set<string> viewElementsAllowed;
|
||||
set<string> viewListsAllowed;
|
||||
map < string, set < string > > funcsAllowed;
|
||||
void SetFunctionDefinitions(void);
|
||||
public:
|
||||
cTemplateView(void);
|
||||
virtual ~cTemplateView(void);
|
||||
virtual string GetSubViewName(eSubView sv) { return ""; };
|
||||
virtual string GetViewElementName(eViewElement ve) { return ""; };
|
||||
virtual string GetViewListName(eViewList vl) { return ""; };
|
||||
virtual void AddSubView(string sSubView, cTemplateView *subView) {};
|
||||
virtual void AddPixmap(string sViewElement, cTemplatePixmap *pix, bool debugViewElement) {};
|
||||
virtual void AddViewList(string sViewList, cTemplateViewList *viewList) {};
|
||||
virtual void AddViewTab(cTemplateViewTab *viewTab) {};
|
||||
//Setter Functions
|
||||
void SetGlobals(cGlobals *globals) { this->globals = globals; };
|
||||
void SetParameters(vector<pair<string, string> > ¶ms);
|
||||
void SetContainer(int x, int y, int width, int height);
|
||||
//access view elements
|
||||
cTemplateViewElement *GetViewElement(eViewElement ve);
|
||||
void InitViewElementIterator(void);
|
||||
cTemplateViewElement *GetNextViewElement(void);
|
||||
//access list elements
|
||||
cTemplateViewList *GetViewList(eViewList vl);
|
||||
void InitViewListIterator(void);
|
||||
cTemplateViewList *GetNextViewList(void);
|
||||
//access tabs
|
||||
void InitViewTabIterator(void);
|
||||
cTemplateViewTab *GetNextViewTab(void);
|
||||
//access sub views
|
||||
cTemplateView *GetSubView(eSubView sv);
|
||||
void InitSubViewIterator(void);
|
||||
cTemplateView *GetNextSubView(void);
|
||||
//Getter Functions
|
||||
const char *GetViewName(void) { return viewName.c_str(); };
|
||||
int GetNumericParameter(eParamType type);
|
||||
cRect GetOsdSize(void);
|
||||
int GetNumPixmaps(void);
|
||||
int GetNumPixmapsViewElement(eViewElement ve);
|
||||
int GetNumListViewMenuItems(void);
|
||||
bool GetScalingWindow(cRect &scalingWindow);
|
||||
//Checks for parsing template XML files
|
||||
bool ValidSubView(const char *subView);
|
||||
bool ValidViewElement(const char *viewElement);
|
||||
bool ValidViewList(const char *viewList);
|
||||
bool ValidFunction(const char *func);
|
||||
bool ValidAttribute(const char *func, const char *att);
|
||||
//Caching
|
||||
void Translate(void);
|
||||
void PreCache(bool isSubview);
|
||||
//Debug
|
||||
void Debug(void);
|
||||
};
|
||||
|
||||
// --- cTemplateViewChannel -------------------------------------------------------------
|
||||
|
||||
class cTemplateViewChannel : public cTemplateView {
|
||||
private:
|
||||
void SetViewElements(void);
|
||||
void SetViewLists(void);
|
||||
public:
|
||||
cTemplateViewChannel(void);
|
||||
virtual ~cTemplateViewChannel(void);
|
||||
string GetViewElementName(eViewElement ve);
|
||||
void AddPixmap(string viewElement, cTemplatePixmap *pix, bool debugViewElement);
|
||||
};
|
||||
|
||||
// --- cTemplateViewMenu -------------------------------------------------------------
|
||||
|
||||
class cTemplateViewMenu : public cTemplateView {
|
||||
private:
|
||||
void SetSubViews(void);
|
||||
void SetViewElements(void);
|
||||
void SetViewLists(void);
|
||||
public:
|
||||
cTemplateViewMenu(void);
|
||||
virtual ~cTemplateViewMenu(void);
|
||||
string GetSubViewName(eSubView sv);
|
||||
string GetViewElementName(eViewElement ve);
|
||||
string GetViewListName(eViewList vl);
|
||||
void AddSubView(string sSubView, cTemplateView *subView);
|
||||
void AddPixmap(string viewElement, cTemplatePixmap *pix, bool debugViewElement);
|
||||
void AddViewList(string sViewList, cTemplateViewList *viewList);
|
||||
void AddViewTab(cTemplateViewTab *viewTab);
|
||||
};
|
||||
|
||||
// --- cTemplateViewMessage -------------------------------------------------------------
|
||||
|
||||
class cTemplateViewMessage : public cTemplateView {
|
||||
private:
|
||||
void SetViewElements(void);
|
||||
public:
|
||||
cTemplateViewMessage(void);
|
||||
virtual ~cTemplateViewMessage(void);
|
||||
string GetViewElementName(eViewElement ve);
|
||||
void AddPixmap(string viewElement, cTemplatePixmap *pix, bool debugViewElement);
|
||||
};
|
||||
|
||||
// --- cTemplateViewReplay -------------------------------------------------------------
|
||||
|
||||
class cTemplateViewReplay : public cTemplateView {
|
||||
private:
|
||||
void SetViewElements(void);
|
||||
public:
|
||||
cTemplateViewReplay(void);
|
||||
virtual ~cTemplateViewReplay(void);
|
||||
string GetViewElementName(eViewElement ve);
|
||||
void AddPixmap(string viewElement, cTemplatePixmap *pix, bool debugViewElement);
|
||||
};
|
||||
|
||||
// --- cTemplateViewVolume -------------------------------------------------------------
|
||||
|
||||
class cTemplateViewVolume : public cTemplateView {
|
||||
private:
|
||||
void SetViewElements(void);
|
||||
public:
|
||||
cTemplateViewVolume(void);
|
||||
virtual ~cTemplateViewVolume(void);
|
||||
string GetViewElementName(eViewElement ve);
|
||||
void AddPixmap(string viewElement, cTemplatePixmap *pix, bool debugViewElement);
|
||||
};
|
||||
|
||||
// --- cTemplateViewAudioTracks -------------------------------------------------------------
|
||||
|
||||
class cTemplateViewAudioTracks : public cTemplateView {
|
||||
private:
|
||||
void SetViewElements(void);
|
||||
void SetViewLists(void);
|
||||
public:
|
||||
cTemplateViewAudioTracks(void);
|
||||
virtual ~cTemplateViewAudioTracks(void);
|
||||
string GetViewElementName(eViewElement ve);
|
||||
string GetViewListName(eViewList vl);
|
||||
void AddPixmap(string viewElement, cTemplatePixmap *pix, bool debugViewElement);
|
||||
void AddViewList(string sViewList, cTemplateViewList *viewList);
|
||||
};
|
||||
|
||||
#endif //__TEMPLATEVIEW_H
|
128
libtemplate/templateviewelement.c
Normal file
@ -0,0 +1,128 @@
|
||||
#include "templateviewelement.h"
|
||||
#include "../config.h"
|
||||
|
||||
cTemplateViewElement::cTemplateViewElement(void) {
|
||||
debugTokens = false;
|
||||
parameters = NULL;
|
||||
containerX = 0;
|
||||
containerY = 0;
|
||||
containerWidth = 0;
|
||||
containerHeight = 0;
|
||||
pixOffset = -1;
|
||||
}
|
||||
|
||||
cTemplateViewElement::~cTemplateViewElement(void) {
|
||||
if (parameters)
|
||||
delete parameters;
|
||||
for (vector<cTemplatePixmap*>::iterator it = viewPixmaps.begin(); it != viewPixmaps.end(); it++) {
|
||||
delete (*it);
|
||||
}
|
||||
}
|
||||
|
||||
void cTemplateViewElement::SetContainer(int x, int y, int width, int height) {
|
||||
containerX = x;
|
||||
containerY = y;
|
||||
containerWidth = width;
|
||||
containerHeight = height;
|
||||
}
|
||||
|
||||
void cTemplateViewElement::SetGlobals(cGlobals *globals) {
|
||||
this->globals = globals;
|
||||
for (vector<cTemplatePixmap*>::iterator pix = viewPixmaps.begin(); pix != viewPixmaps.end(); pix++) {
|
||||
(*pix)->SetGlobals(globals);
|
||||
}
|
||||
}
|
||||
|
||||
void cTemplateViewElement::SetParameters(vector<pair<string, string> > ¶ms) {
|
||||
parameters = new cTemplateFunction(ftViewElement);
|
||||
parameters->SetGlobals(globals);
|
||||
parameters->SetParameters(params);
|
||||
}
|
||||
|
||||
bool cTemplateViewElement::CalculateParameters(void) {
|
||||
if (!parameters)
|
||||
return true;
|
||||
bool paramsValid = true;
|
||||
parameters->SetContainer(containerX, containerY, containerWidth, containerHeight);
|
||||
parameters->SetGlobals(globals);
|
||||
paramsValid = parameters->CalculateParameters();
|
||||
|
||||
return paramsValid;
|
||||
}
|
||||
|
||||
bool cTemplateViewElement::CalculatePixmapParameters(void) {
|
||||
bool paramsValid = true;
|
||||
for (vector<cTemplatePixmap*>::iterator pix = viewPixmaps.begin(); pix != viewPixmaps.end(); pix++) {
|
||||
(*pix)->SetContainer(containerX, containerY, containerWidth, containerHeight);
|
||||
(*pix)->SetGlobals(globals);
|
||||
paramsValid = paramsValid && (*pix)->CalculateParameters();
|
||||
}
|
||||
return paramsValid;
|
||||
}
|
||||
|
||||
bool cTemplateViewElement::CalculatePixmapParametersList(int orientation, int numElements) {
|
||||
bool paramsValid = true;
|
||||
for (vector<cTemplatePixmap*>::iterator pix = viewPixmaps.begin(); pix != viewPixmaps.end(); pix++) {
|
||||
(*pix)->SetContainer(containerX, containerY, containerWidth, containerHeight);
|
||||
(*pix)->SetGlobals(globals);
|
||||
if (orientation == orHorizontal) {
|
||||
if (numElements > 0) {
|
||||
int width = containerWidth / numElements;
|
||||
(*pix)->SetWidth(width);
|
||||
}
|
||||
} else if (orientation == orVertical) {
|
||||
if (numElements > 0) {
|
||||
int height = containerHeight / numElements;
|
||||
(*pix)->SetHeight(height);
|
||||
}
|
||||
}
|
||||
paramsValid = paramsValid && (*pix)->CalculateParameters();
|
||||
}
|
||||
return paramsValid;
|
||||
}
|
||||
|
||||
int cTemplateViewElement::GetNumericParameter(eParamType type) {
|
||||
if (!parameters)
|
||||
return -1;
|
||||
return parameters->GetNumericParameter(type);
|
||||
}
|
||||
|
||||
void cTemplateViewElement::InitIterator(void) {
|
||||
pixIterator = viewPixmaps.begin();
|
||||
}
|
||||
|
||||
cTemplatePixmap *cTemplateViewElement::GetNextPixmap(void) {
|
||||
if (pixIterator == viewPixmaps.end())
|
||||
return NULL;
|
||||
cTemplatePixmap *pix = *pixIterator;
|
||||
pixIterator++;
|
||||
return pix;
|
||||
}
|
||||
|
||||
cTemplateFunction *cTemplateViewElement::GetFunction(string name) {
|
||||
InitIterator();
|
||||
cTemplatePixmap *pix = NULL;
|
||||
while (pix = GetNextPixmap()) {
|
||||
pix->InitIterator();
|
||||
cTemplateFunction *func = NULL;
|
||||
while(func = pix->GetNextFunction()) {
|
||||
if (func->GetType() == ftDrawText) {
|
||||
string funcName = func->GetParameter(ptName);
|
||||
if (!funcName.compare(name))
|
||||
return func;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void cTemplateViewElement::Debug(void) {
|
||||
esyslog("skindesigner: viewelement container size x: %d, y: %d, width: %d, height %d", containerX, containerY, containerWidth, containerHeight);
|
||||
if (parameters)
|
||||
parameters->Debug();
|
||||
for (vector<cTemplatePixmap*>::iterator it = viewPixmaps.begin(); it != viewPixmaps.end(); it++) {
|
||||
(*it)->Debug();
|
||||
}
|
||||
}
|
99
libtemplate/templateviewelement.h
Normal file
@ -0,0 +1,99 @@
|
||||
#ifndef __TEMPLATEVIEWELEMENT_H
|
||||
#define __TEMPLATEVIEWELEMENT_H
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
#include "templatepixmap.h"
|
||||
#include "templatefunction.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// --- cTemplateViewElement -------------------------------------------------------------
|
||||
|
||||
enum eViewElement {
|
||||
//Common ViewElements
|
||||
veUndefined,
|
||||
veBackground,
|
||||
veDateTime,
|
||||
veMessage,
|
||||
//DisplayChannel ViewElements
|
||||
veChannelInfo,
|
||||
veChannelGroup,
|
||||
veEpgInfo,
|
||||
veProgressBar,
|
||||
veProgressBarBack,
|
||||
veStatusInfo,
|
||||
veScreenResolution,
|
||||
veSignalQuality,
|
||||
veSignalQualityBack,
|
||||
veScraperContent,
|
||||
//DisplayMenu ViewElements
|
||||
veHeader,
|
||||
veButtons,
|
||||
veDiscUsage,
|
||||
veSystemLoad,
|
||||
veTimers,
|
||||
veDevices,
|
||||
veMenuItem,
|
||||
veMenuCurrentItemDetail,
|
||||
veScrollbar,
|
||||
veDetailHeader,
|
||||
veTabLabels,
|
||||
//DisplayReplay ViewElements
|
||||
veRecTitle,
|
||||
veRecInfo,
|
||||
veRecCurrent,
|
||||
veRecTotal,
|
||||
veRecProgressBar,
|
||||
veCuttingMarks,
|
||||
veControlIcons,
|
||||
veControlIconsModeOnly,
|
||||
veBackgroundModeOnly,
|
||||
veRecJump,
|
||||
//DisplayVolume ViewElements
|
||||
veVolume
|
||||
};
|
||||
|
||||
class cTemplateViewElement {
|
||||
protected:
|
||||
bool debugTokens;
|
||||
cGlobals *globals;
|
||||
cTemplateFunction *parameters;
|
||||
int containerX;
|
||||
int containerY;
|
||||
int containerWidth;
|
||||
int containerHeight;
|
||||
vector<cTemplatePixmap*> viewPixmaps;
|
||||
vector<cTemplatePixmap*>::iterator pixIterator;
|
||||
int pixOffset;
|
||||
public:
|
||||
cTemplateViewElement(void);
|
||||
virtual ~cTemplateViewElement(void);
|
||||
void SetParameters(vector<pair<string, string> > ¶ms);
|
||||
bool CalculateParameters(void);
|
||||
bool CalculatePixmapParameters(void);
|
||||
bool CalculatePixmapParametersList(int orientation, int numElements);
|
||||
int GetNumericParameter(eParamType type);
|
||||
void AddPixmap(cTemplatePixmap *pix) { viewPixmaps.push_back(pix); };
|
||||
virtual void SetGlobals(cGlobals *globals);
|
||||
void SetContainer(int x, int y, int width, int height);
|
||||
void SetPixOffset(int offset) { pixOffset = offset; };
|
||||
int GetPixOffset(void) { return pixOffset; };
|
||||
virtual int GetNumPixmaps(void) { return viewPixmaps.size(); };
|
||||
void InitIterator(void);
|
||||
cTemplatePixmap *GetNextPixmap(void);
|
||||
cTemplateFunction *GetFunction(string name);
|
||||
void ActivateDebugTokens(void) {debugTokens = true; };
|
||||
bool DebugTokens(void) { return debugTokens; };
|
||||
virtual void Debug(void);
|
||||
};
|
||||
|
||||
#endif //__TEMPLATEVIEWELEMENT_H
|
138
libtemplate/templateviewlist.c
Normal file
@ -0,0 +1,138 @@
|
||||
#include "templateviewlist.h"
|
||||
#include "../config.h"
|
||||
|
||||
cTemplateViewList::cTemplateViewList(void) : cTemplateViewElement() {
|
||||
listElement = NULL;
|
||||
currentElement = NULL;
|
||||
}
|
||||
|
||||
cTemplateViewList::~cTemplateViewList(void) {
|
||||
if (listElement)
|
||||
delete listElement;
|
||||
if (currentElement)
|
||||
delete currentElement;
|
||||
}
|
||||
|
||||
void cTemplateViewList::SetGlobals(cGlobals *globals) {
|
||||
cTemplateViewElement::SetGlobals(globals);
|
||||
if (listElement)
|
||||
listElement->SetGlobals(globals);
|
||||
if (currentElement)
|
||||
currentElement->SetGlobals(globals);
|
||||
}
|
||||
|
||||
bool cTemplateViewList::CalculateListParameters(void) {
|
||||
if (!parameters)
|
||||
return false;
|
||||
parameters->SetContainer(containerX, containerY, containerWidth, containerHeight);
|
||||
parameters->SetGlobals(globals);
|
||||
bool paramsValid = parameters->CalculateParameters();
|
||||
if (!listElement)
|
||||
return false;
|
||||
listElement->SetContainer(parameters->GetNumericParameter(ptX),
|
||||
parameters->GetNumericParameter(ptY),
|
||||
parameters->GetNumericParameter(ptWidth),
|
||||
parameters->GetNumericParameter(ptHeight));
|
||||
paramsValid = listElement->CalculateParameters();
|
||||
paramsValid = listElement->CalculatePixmapParametersList(parameters->GetNumericParameter(ptOrientation),
|
||||
parameters->GetNumericParameter(ptNumElements));
|
||||
if (!currentElement)
|
||||
return paramsValid;
|
||||
currentElement->SetContainer(parameters->GetNumericParameter(ptX),
|
||||
parameters->GetNumericParameter(ptY),
|
||||
parameters->GetNumericParameter(ptWidth),
|
||||
parameters->GetNumericParameter(ptHeight));
|
||||
paramsValid = currentElement->CalculateParameters();
|
||||
paramsValid = currentElement->CalculatePixmapParameters();
|
||||
currentElement->SetPixOffset(0);
|
||||
return paramsValid;
|
||||
}
|
||||
|
||||
bool cTemplateViewList::CalculateListParameters(map < string, int > *intTokens) {
|
||||
if (!parameters)
|
||||
return false;
|
||||
parameters->ClearDynamicParameters();
|
||||
parameters->SetIntTokens(intTokens);
|
||||
parameters->ParseParameters();
|
||||
parameters->UnsetIntTokens();
|
||||
|
||||
listElement->SetContainer(parameters->GetNumericParameter(ptX),
|
||||
parameters->GetNumericParameter(ptY),
|
||||
parameters->GetNumericParameter(ptWidth),
|
||||
parameters->GetNumericParameter(ptHeight));
|
||||
bool paramsValid = listElement->CalculateParameters();
|
||||
paramsValid = listElement->CalculatePixmapParametersList(parameters->GetNumericParameter(ptOrientation),
|
||||
parameters->GetNumericParameter(ptNumElements));
|
||||
return paramsValid;
|
||||
}
|
||||
|
||||
int cTemplateViewList::GetAverageFontWidth(void) {
|
||||
int defaultAverageFontWidth = 20;
|
||||
|
||||
if (!listElement)
|
||||
return defaultAverageFontWidth;
|
||||
|
||||
int numItems = GetNumericParameter(ptNumElements);
|
||||
int listHeight = GetNumericParameter(ptHeight);
|
||||
if (listHeight <= 0)
|
||||
return defaultAverageFontWidth;
|
||||
int itemHeight = (double)listHeight / (double)numItems;
|
||||
string fontFuncName = parameters->GetParameter(ptDeterminateFont);
|
||||
|
||||
cTemplateFunction *fontFunc = listElement->GetFunction(fontFuncName);
|
||||
if (!fontFunc)
|
||||
return defaultAverageFontWidth;
|
||||
|
||||
string fontNameToken = fontFunc->GetParameter(ptFont);
|
||||
string paramFontSize = fontFunc->GetParameter(ptFontSize);
|
||||
|
||||
string fontName = "";
|
||||
if ((fontNameToken.find("{") == 0) && (fontNameToken.find("}") == (fontNameToken.size()-1))) {
|
||||
fontNameToken = fontNameToken.substr(1, fontNameToken.size()-2);
|
||||
map<string,string>::iterator hit = globals->fonts.find(fontNameToken);
|
||||
if (hit != globals->fonts.end()) {
|
||||
fontName = hit->second;
|
||||
} else {
|
||||
map<string,string>::iterator def = globals->fonts.find("vdrOsd");
|
||||
if (def == globals->fonts.end())
|
||||
return defaultAverageFontWidth;
|
||||
fontName = def->second;
|
||||
}
|
||||
} else {
|
||||
//if no token, directly use input
|
||||
fontName = fontNameToken;
|
||||
}
|
||||
|
||||
cNumericParameter pFontSize(paramFontSize);
|
||||
pFontSize.SetGlobals(globals);
|
||||
pFontSize.SetAreaSize(1000, itemHeight);
|
||||
pFontSize.SetVertical();
|
||||
int fontSize = pFontSize.Parse(paramFontSize);
|
||||
if (!pFontSize.Valid())
|
||||
return defaultAverageFontWidth;
|
||||
|
||||
int averageFontWidth = fontManager->Width(fontName, fontSize, "x") + 3;
|
||||
return averageFontWidth;
|
||||
}
|
||||
|
||||
int cTemplateViewList::GetMenuItemWidth(void) {
|
||||
return GetNumericParameter(ptMenuItemWidth);
|
||||
}
|
||||
|
||||
|
||||
int cTemplateViewList::GetNumPixmaps(void) {
|
||||
if (!listElement)
|
||||
return 0;
|
||||
return listElement->GetNumPixmaps();
|
||||
}
|
||||
|
||||
void cTemplateViewList::Debug(void) {
|
||||
if (parameters)
|
||||
parameters->Debug();
|
||||
esyslog("skindesigner: --- listelement: ");
|
||||
if (listElement)
|
||||
listElement->Debug();
|
||||
esyslog("skindesigner: --- currentelement: ");
|
||||
if (currentElement)
|
||||
currentElement->Debug();
|
||||
}
|
49
libtemplate/templateviewlist.h
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef __TEMPLATEVIEWLIST_H
|
||||
#define __TEMPLATEVIEWLIST_H
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
#include "templateviewelement.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// --- cTemplateViewList -------------------------------------------------------------
|
||||
|
||||
enum eViewList {
|
||||
vlUndefined,
|
||||
//DisplayChannel ViewLists
|
||||
vlDvbDeviceInfoList,
|
||||
//DisplayMenu ViewLists
|
||||
vlTimerList,
|
||||
vlMenuItem
|
||||
};
|
||||
|
||||
class cTemplateViewList : public cTemplateViewElement {
|
||||
private:
|
||||
cTemplateViewElement *listElement;
|
||||
cTemplateViewElement *currentElement;
|
||||
public:
|
||||
cTemplateViewList(void);
|
||||
~cTemplateViewList(void);
|
||||
void SetGlobals(cGlobals *globals);
|
||||
void AddListElement(cTemplateViewElement *listElement) { this->listElement = listElement; };
|
||||
void AddCurrentElement(cTemplateViewElement *currentElement) { this->currentElement = currentElement; };
|
||||
bool CalculateListParameters(void);
|
||||
bool CalculateListParameters(map < string, int > *intTokens);
|
||||
cTemplateViewElement *GetListElement(void) { return listElement; };
|
||||
cTemplateViewElement *GetListElementCurrent(void) { return currentElement; };
|
||||
int GetAverageFontWidth(void);
|
||||
int GetMenuItemWidth(void);
|
||||
int GetNumPixmaps(void);
|
||||
void Debug(void);
|
||||
};
|
||||
|
||||
#endif //__TEMPLATEVIEWLIST_H
|
38
libtemplate/templateviewtab.c
Normal file
@ -0,0 +1,38 @@
|
||||
#include "templateviewtab.h"
|
||||
|
||||
cTemplateViewTab::cTemplateViewTab(void) : cTemplatePixmap() {
|
||||
scrollStep = -1;
|
||||
}
|
||||
|
||||
cTemplateViewTab::~cTemplateViewTab(void) {
|
||||
}
|
||||
|
||||
int cTemplateViewTab::GetScrollStep(void) {
|
||||
if (scrollStep > 0)
|
||||
return scrollStep;
|
||||
int pixWidth = GetNumericParameter(ptWidth);
|
||||
int pixHeight = GetNumericParameter(ptHeight);
|
||||
string scrollHeight = parameters->GetParameter(ptScrollHeight);
|
||||
|
||||
cNumericParameter p(scrollHeight);
|
||||
p.SetAreaSize(pixWidth, pixHeight);
|
||||
string parsedValue = "";
|
||||
scrollStep = p.Parse(parsedValue);
|
||||
if (scrollStep < 1)
|
||||
scrollStep = 50;
|
||||
return scrollStep;
|
||||
}
|
||||
|
||||
string cTemplateViewTab::GetName(void) {
|
||||
return parameters->GetParameter(ptName);
|
||||
}
|
||||
|
||||
void cTemplateViewTab::SetName(string trans) {
|
||||
parameters->SetParameter(ptName, trans);
|
||||
}
|
||||
|
||||
void cTemplateViewTab::Debug(void) {
|
||||
esyslog("skindesigner: cTemplateViewTab Debug %s", GetName().c_str());
|
||||
cTemplatePixmap::Debug();
|
||||
esyslog("skindesigner: -------------------------------------------------------");
|
||||
}
|
31
libtemplate/templateviewtab.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef __TEMPLATEVIEWTAB_H
|
||||
#define __TEMPLATEVIEWTAB_H
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include "templatepixmap.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// --- cTemplateViewTab -------------------------------------------------------------
|
||||
|
||||
class cTemplateViewTab : public cTemplatePixmap {
|
||||
private:
|
||||
int scrollStep;
|
||||
public:
|
||||
cTemplateViewTab(void);
|
||||
~cTemplateViewTab(void);
|
||||
int GetScrollStep(void);
|
||||
string GetName(void);
|
||||
void SetName(string trans);
|
||||
void Debug(void);
|
||||
};
|
||||
|
||||
#endif //__TEMPLATEVIEWTAB_H
|
728
libtemplate/xmlparser.c
Normal file
@ -0,0 +1,728 @@
|
||||
#include "xmlparser.h"
|
||||
#include "../config.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
void SkinDesignerXMLErrorHandler (void * userData, xmlErrorPtr error) {
|
||||
esyslog("skindesigner: Error in XML: %s", error->message);
|
||||
}
|
||||
|
||||
cXmlParser::cXmlParser(void) {
|
||||
doc = NULL;
|
||||
root = NULL;
|
||||
ctxt = NULL;
|
||||
|
||||
xmlInitParser();
|
||||
initGenericErrorDefaultFunc(NULL);
|
||||
xmlSetStructuredErrorFunc(NULL, SkinDesignerXMLErrorHandler);
|
||||
ctxt = xmlNewParserCtxt();
|
||||
}
|
||||
|
||||
cXmlParser::~cXmlParser() {
|
||||
DeleteDocument();
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
xmlCleanupParser();
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* PUBLIC Functions
|
||||
*********************************************************************/
|
||||
bool cXmlParser::ReadView(cTemplateView *view, string xmlFile) {
|
||||
this->view = view;
|
||||
|
||||
string xmlPath = GetPath(xmlFile);
|
||||
|
||||
if (ctxt == NULL) {
|
||||
esyslog("skindesigner: Failed to allocate parser context");
|
||||
return false;
|
||||
}
|
||||
|
||||
doc = xmlCtxtReadFile(ctxt, xmlPath.c_str(), NULL, XML_PARSE_NOENT | XML_PARSE_DTDVALID);
|
||||
|
||||
if (doc == NULL) {
|
||||
esyslog("skindesigner: ERROR: TemplateView %s not parsed successfully.", xmlPath.c_str());
|
||||
return false;
|
||||
}
|
||||
if (ctxt->valid == 0) {
|
||||
esyslog("skindesigner: Failed to validate %s", xmlPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
root = xmlDocGetRootElement(doc);
|
||||
|
||||
if (root == NULL) {
|
||||
esyslog("skindesigner: ERROR: TemplateView %s is empty", xmlPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (xmlStrcmp(root->name, (const xmlChar *) view->GetViewName())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cXmlParser::ReadGlobals(cGlobals *globals, string xmlFile) {
|
||||
this->globals = globals;
|
||||
|
||||
string xmlPath = GetPath(xmlFile);
|
||||
|
||||
if (ctxt == NULL) {
|
||||
esyslog("skindesigner: Failed to allocate parser context");
|
||||
return false;
|
||||
}
|
||||
|
||||
doc = xmlCtxtReadFile(ctxt, xmlPath.c_str(), NULL, XML_PARSE_NOENT | XML_PARSE_DTDVALID);
|
||||
|
||||
if (doc == NULL ) {
|
||||
esyslog("skindesigner: ERROR: Globals %s not parsed successfully.", xmlPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
root = xmlDocGetRootElement(doc);
|
||||
|
||||
if (ctxt->valid == 0) {
|
||||
esyslog("skindesigner: Failed to validate %s", xmlPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (root == NULL) {
|
||||
esyslog("skindesigner: ERROR: Globals %s is empty", xmlPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (xmlStrcmp(root->name, (const xmlChar *) "globals")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cXmlParser::ParseView(void) {
|
||||
vector<pair<string, string> > rootAttribs;
|
||||
ParseAttributes(root->properties, root, rootAttribs);
|
||||
|
||||
if (!view)
|
||||
return false;
|
||||
|
||||
view->SetParameters(rootAttribs);
|
||||
|
||||
xmlNodePtr node = root->xmlChildrenNode;
|
||||
|
||||
while (node != NULL) {
|
||||
|
||||
if (node->type != XML_ELEMENT_NODE) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (view->ValidSubView((const char*)node->name)) {
|
||||
ParseSubView(node);
|
||||
} else if (view->ValidViewElement((const char*)node->name)) {
|
||||
bool debugViewElement = DebugViewElement(node);
|
||||
ParseViewElement(node->name, node->xmlChildrenNode, debugViewElement);
|
||||
} else if (view->ValidViewList((const char*)node->name)) {
|
||||
ParseViewList(node);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool cXmlParser::ParseGlobals(void) {
|
||||
xmlNodePtr node = root->xmlChildrenNode;
|
||||
|
||||
while (node != NULL) {
|
||||
if (node->type != XML_ELEMENT_NODE) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
if (!xmlStrcmp(node->name, (const xmlChar *) "colors")) {
|
||||
ParseGlobalColors(node->xmlChildrenNode);
|
||||
node = node->next;
|
||||
continue;
|
||||
} else if (!xmlStrcmp(node->name, (const xmlChar *) "variables")) {
|
||||
ParseGlobalVariables(node->xmlChildrenNode);
|
||||
node = node->next;
|
||||
continue;
|
||||
} else if (!xmlStrcmp(node->name, (const xmlChar *) "fonts")) {
|
||||
ParseGlobalFonts(node->xmlChildrenNode);
|
||||
node = node->next;
|
||||
continue;
|
||||
} else if (!xmlStrcmp(node->name, (const xmlChar *) "translations")) {
|
||||
ParseTranslations(node->xmlChildrenNode);
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void cXmlParser::DeleteDocument(void) {
|
||||
if (doc) {
|
||||
xmlFreeDoc(doc);
|
||||
doc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* PRIVATE Functions
|
||||
*********************************************************************/
|
||||
|
||||
string cXmlParser::GetPath(string xmlFile) {
|
||||
return *cString::sprintf("%s%s/xmlfiles/%s", *config.skinPath, Setup.OSDTheme, xmlFile.c_str());
|
||||
}
|
||||
|
||||
void cXmlParser::ParseGlobalColors(xmlNodePtr node) {
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
while (node != NULL) {
|
||||
|
||||
if (node->type != XML_ELEMENT_NODE) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
if (xmlStrcmp(node->name, (const xmlChar *) "color")) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
xmlAttrPtr attr = node->properties;
|
||||
if (attr == NULL) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
xmlChar *colName = NULL;
|
||||
xmlChar *colValue = NULL;
|
||||
bool ok = false;
|
||||
while (NULL != attr) {
|
||||
if (xmlStrcmp(attr->name, (const xmlChar *) "name")) {
|
||||
attr = attr->next;
|
||||
continue;
|
||||
}
|
||||
ok = true;
|
||||
colName = xmlGetProp(node, attr->name);
|
||||
attr = attr->next;
|
||||
}
|
||||
if (ok) {
|
||||
colValue = xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
if (colName && colValue)
|
||||
InsertColor((const char*)colName, (const char*)colValue);
|
||||
}
|
||||
if (colName)
|
||||
xmlFree(colName);
|
||||
if (colValue)
|
||||
xmlFree(colValue);
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
void cXmlParser::InsertColor(string name, string value) {
|
||||
if (value.size() != 8)
|
||||
return;
|
||||
std::stringstream str;
|
||||
str << value;
|
||||
tColor colVal;
|
||||
str >> std::hex >> colVal;
|
||||
globals->colors.insert(pair<string, tColor>(name, colVal));
|
||||
}
|
||||
|
||||
void cXmlParser::ParseGlobalVariables(xmlNodePtr node) {
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
while (node != NULL) {
|
||||
|
||||
if (node->type != XML_ELEMENT_NODE) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
if (xmlStrcmp(node->name, (const xmlChar *) "var")) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
xmlAttrPtr attr = node->properties;
|
||||
if (attr == NULL) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
xmlChar *varName = NULL;
|
||||
xmlChar *varType = NULL;
|
||||
xmlChar *varValue = NULL;
|
||||
while (NULL != attr) {
|
||||
if (!xmlStrcmp(attr->name, (const xmlChar *) "name")) {
|
||||
varName = xmlGetProp(node, attr->name);
|
||||
} else if (!xmlStrcmp(attr->name, (const xmlChar *) "type")) {
|
||||
varType = xmlGetProp(node, attr->name);
|
||||
} else {
|
||||
attr = attr->next;
|
||||
continue;
|
||||
}
|
||||
attr = attr->next;
|
||||
}
|
||||
varValue = xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
if (varName && varType && varValue)
|
||||
InsertVariable((const char*)varName, (const char*)varType, (const char*)varValue);
|
||||
if (varName)
|
||||
xmlFree(varName);
|
||||
if (varType)
|
||||
xmlFree(varType);
|
||||
if (varValue)
|
||||
xmlFree(varValue);
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
void cXmlParser::InsertVariable(string name, string type, string value) {
|
||||
if (!type.compare("int")) {
|
||||
int val = atoi(value.c_str());
|
||||
globals->intVars.insert(pair<string, int>(name, val));
|
||||
} else if (!type.compare("string")) {
|
||||
globals->stringVars.insert(pair<string, string>(name, value));
|
||||
}
|
||||
}
|
||||
|
||||
void cXmlParser::ParseGlobalFonts(xmlNodePtr node) {
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
while (node != NULL) {
|
||||
|
||||
if (node->type != XML_ELEMENT_NODE) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
if (xmlStrcmp(node->name, (const xmlChar *) "font")) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
xmlAttrPtr attr = node->properties;
|
||||
if (attr == NULL) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
xmlChar *fontName = NULL;
|
||||
xmlChar *fontValue = NULL;
|
||||
bool ok = false;
|
||||
while (NULL != attr) {
|
||||
if (xmlStrcmp(attr->name, (const xmlChar *) "name")) {
|
||||
attr = attr->next;
|
||||
continue;
|
||||
}
|
||||
ok = true;
|
||||
fontName = xmlGetProp(node, attr->name);
|
||||
attr = attr->next;
|
||||
}
|
||||
if (ok) {
|
||||
fontValue = xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
if (fontName && fontValue)
|
||||
globals->fonts.insert(pair<string, string>((const char*)fontName, (const char*)fontValue));
|
||||
}
|
||||
if (fontName)
|
||||
xmlFree(fontName);
|
||||
if (fontValue)
|
||||
xmlFree(fontValue);
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
void cXmlParser::ParseTranslations(xmlNodePtr node) {
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
while (node != NULL) {
|
||||
|
||||
if (node->type != XML_ELEMENT_NODE) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
if (xmlStrcmp(node->name, (const xmlChar *) "token")) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
xmlAttrPtr attr = node->properties;
|
||||
if (attr == NULL) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
xmlChar *tokenName;
|
||||
bool ok = false;
|
||||
while (NULL != attr) {
|
||||
if (xmlStrcmp(attr->name, (const xmlChar *) "name")) {
|
||||
attr = attr->next;
|
||||
continue;
|
||||
}
|
||||
ok = true;
|
||||
tokenName = xmlGetProp(node, attr->name);
|
||||
attr = attr->next;
|
||||
}
|
||||
if (!ok)
|
||||
continue;
|
||||
map < string, string > tokenTranslations;
|
||||
xmlNodePtr nodeTrans = node->xmlChildrenNode;
|
||||
while (nodeTrans != NULL) {
|
||||
if (nodeTrans->type != XML_ELEMENT_NODE) {
|
||||
nodeTrans = nodeTrans->next;
|
||||
continue;
|
||||
}
|
||||
xmlChar *language = NULL;
|
||||
if (xmlStrcmp(nodeTrans->name, (const xmlChar *) "trans")) {
|
||||
nodeTrans = nodeTrans->next;
|
||||
continue;
|
||||
}
|
||||
xmlAttrPtr attrTrans = nodeTrans->properties;
|
||||
if (attrTrans == NULL) {
|
||||
nodeTrans = nodeTrans->next;
|
||||
continue;
|
||||
}
|
||||
ok = false;
|
||||
|
||||
while (NULL != attrTrans) {
|
||||
if (!ok && xmlStrcmp(attrTrans->name, (const xmlChar *) "lang")) {
|
||||
attrTrans = attrTrans->next;
|
||||
continue;
|
||||
}
|
||||
ok = true;
|
||||
language = xmlGetProp(nodeTrans, attrTrans->name);
|
||||
attrTrans = attrTrans->next;
|
||||
}
|
||||
if (!ok)
|
||||
continue;
|
||||
xmlChar *value = NULL;
|
||||
value = xmlNodeListGetString(doc, nodeTrans->xmlChildrenNode, 1);
|
||||
if (language && value)
|
||||
tokenTranslations.insert(pair<string, string>((const char*)language, (const char*)value));
|
||||
if (language)
|
||||
xmlFree(language);
|
||||
if (value)
|
||||
xmlFree(value);
|
||||
nodeTrans = nodeTrans->next;
|
||||
}
|
||||
globals->translations.insert(pair<string, map < string, string > >((const char*)tokenName, tokenTranslations));
|
||||
xmlFree(tokenName);
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
bool cXmlParser::ParseSubView(xmlNodePtr node) {
|
||||
if (!node)
|
||||
return false;
|
||||
|
||||
if (!view)
|
||||
return false;
|
||||
|
||||
cTemplateView *subView = new cTemplateViewMenu();
|
||||
view->AddSubView((const char*)node->name, subView);
|
||||
|
||||
vector<pair<string, string> > subViewAttribs;
|
||||
ParseAttributes(node->properties, node, subViewAttribs);
|
||||
|
||||
subView->SetParameters(subViewAttribs);
|
||||
|
||||
xmlNodePtr childNode = node->xmlChildrenNode;
|
||||
|
||||
while (childNode != NULL) {
|
||||
|
||||
if (childNode->type != XML_ELEMENT_NODE) {
|
||||
childNode = childNode->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (subView->ValidViewElement((const char*)childNode->name)) {
|
||||
bool debugViewElement = DebugViewElement(childNode);
|
||||
ParseViewElement(childNode->name, childNode->xmlChildrenNode, debugViewElement, subView);
|
||||
} else if (subView->ValidViewList((const char*)childNode->name)) {
|
||||
ParseViewList(childNode, subView);
|
||||
} else if (!xmlStrcmp(childNode->name, (const xmlChar *) "tab")) {
|
||||
ParseViewTab(childNode, subView);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
childNode = childNode->next;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void cXmlParser::ParseViewElement(const xmlChar * viewElement, xmlNodePtr node, bool debugVE, cTemplateView *subView) {
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
if (!view)
|
||||
return;
|
||||
|
||||
if (debugVE) {
|
||||
dsyslog("skindesigner: activating debugging of viewElement %s", (const char*)viewElement);
|
||||
}
|
||||
|
||||
while (node != NULL) {
|
||||
|
||||
if (node->type != XML_ELEMENT_NODE) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlStrcmp(node->name, (const xmlChar *) "area") && xmlStrcmp(node->name, (const xmlChar *) "areascroll")) {
|
||||
esyslog("skindesigner: invalid tag \"%s\"", node->name);
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
xmlAttrPtr attr = node->properties;
|
||||
vector<pair<string, string> > attribs;
|
||||
ParseAttributes(attr, node, attribs);
|
||||
|
||||
cTemplatePixmap *pix = new cTemplatePixmap();
|
||||
if (!xmlStrcmp(node->name, (const xmlChar *) "areascroll")) {
|
||||
pix->SetScrolling();
|
||||
}
|
||||
pix->SetParameters(attribs);
|
||||
ParseFunctionCalls(node->xmlChildrenNode, pix);
|
||||
if (subView)
|
||||
subView->AddPixmap((const char*)viewElement, pix, debugVE);
|
||||
else
|
||||
view->AddPixmap((const char*)viewElement, pix, debugVE);
|
||||
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
void cXmlParser::ParseViewList(xmlNodePtr parentNode, cTemplateView *subView) {
|
||||
if (!parentNode || !view)
|
||||
return;
|
||||
|
||||
xmlAttrPtr attr = parentNode->properties;
|
||||
vector<pair<string, string> > attribs;
|
||||
ParseAttributes(attr, parentNode, attribs);
|
||||
|
||||
cTemplateViewList *viewList = new cTemplateViewList();
|
||||
viewList->SetGlobals(globals);
|
||||
viewList->SetParameters(attribs);
|
||||
|
||||
xmlNodePtr node = parentNode->xmlChildrenNode;
|
||||
|
||||
while (node != NULL) {
|
||||
|
||||
if (node->type != XML_ELEMENT_NODE) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!xmlStrcmp(node->name, (const xmlChar *) "currentelement")) {
|
||||
xmlNodePtr childNode = node->xmlChildrenNode;
|
||||
if (!childNode)
|
||||
continue;
|
||||
cTemplateViewElement *currentElement = new cTemplateViewElement();
|
||||
xmlAttrPtr attrCur = node->properties;
|
||||
vector<pair<string, string> > attribsCur;
|
||||
ParseAttributes(attrCur, node, attribsCur);
|
||||
currentElement->SetGlobals(globals);
|
||||
currentElement->SetParameters(attribsCur);
|
||||
bool debugCurrent = false;
|
||||
for (vector<pair<string, string> >::iterator it = attribsCur.begin(); it != attribsCur.end(); it++) {
|
||||
if (!(it->first).compare("debug")) {
|
||||
debugCurrent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (debugCurrent)
|
||||
currentElement->ActivateDebugTokens();
|
||||
while (childNode != NULL) {
|
||||
if (childNode->type != XML_ELEMENT_NODE) {
|
||||
childNode = childNode->next;
|
||||
continue;
|
||||
}
|
||||
if ((!xmlStrcmp(childNode->name, (const xmlChar *) "area")) || (!xmlStrcmp(childNode->name, (const xmlChar *) "areascroll"))) {
|
||||
xmlAttrPtr attrPix = childNode->properties;
|
||||
vector<pair<string, string> > attribsPix;
|
||||
ParseAttributes(attrPix, childNode, attribsPix);
|
||||
cTemplatePixmap *pix = new cTemplatePixmap();
|
||||
pix->SetParameters(attribsPix);
|
||||
ParseFunctionCalls(childNode->xmlChildrenNode, pix);
|
||||
if (!xmlStrcmp(childNode->name, (const xmlChar *) "areascroll")) {
|
||||
pix->SetScrolling();
|
||||
}
|
||||
currentElement->AddPixmap(pix);
|
||||
}
|
||||
childNode = childNode->next;
|
||||
}
|
||||
viewList->AddCurrentElement(currentElement);
|
||||
} else if (!xmlStrcmp(node->name, (const xmlChar *) "listelement")) {
|
||||
bool debugViewList = DebugViewElement(node);
|
||||
xmlNodePtr childNode = node->xmlChildrenNode;
|
||||
if (!childNode)
|
||||
continue;
|
||||
cTemplateViewElement *listElement = new cTemplateViewElement();
|
||||
if (debugViewList)
|
||||
listElement->ActivateDebugTokens();
|
||||
while (childNode != NULL) {
|
||||
if (childNode->type != XML_ELEMENT_NODE) {
|
||||
childNode = childNode->next;
|
||||
continue;
|
||||
}
|
||||
if ((!xmlStrcmp(childNode->name, (const xmlChar *) "area")) || (!xmlStrcmp(childNode->name, (const xmlChar *) "areascroll"))) {
|
||||
xmlAttrPtr attrPix = childNode->properties;
|
||||
vector<pair<string, string> > attribsPix;
|
||||
ParseAttributes(attrPix, childNode, attribsPix);
|
||||
cTemplatePixmap *pix = new cTemplatePixmap();
|
||||
pix->SetParameters(attribsPix);
|
||||
ParseFunctionCalls(childNode->xmlChildrenNode, pix);
|
||||
if (!xmlStrcmp(childNode->name, (const xmlChar *) "areascroll")) {
|
||||
pix->SetScrolling();
|
||||
}
|
||||
listElement->AddPixmap(pix);
|
||||
}
|
||||
childNode = childNode->next;
|
||||
}
|
||||
viewList->AddListElement(listElement);
|
||||
} else {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
if (subView)
|
||||
subView->AddViewList((const char*)parentNode->name, viewList);
|
||||
else
|
||||
view->AddViewList((const char*)parentNode->name, viewList);
|
||||
}
|
||||
|
||||
void cXmlParser::ParseViewTab(xmlNodePtr parentNode, cTemplateView *subView) {
|
||||
if (!parentNode || !view || !subView)
|
||||
return;
|
||||
|
||||
xmlAttrPtr attr = parentNode->properties;
|
||||
vector<pair<string, string> > attribs;
|
||||
ParseAttributes(attr, parentNode, attribs);
|
||||
|
||||
cTemplateViewTab *viewTab = new cTemplateViewTab();
|
||||
viewTab->SetGlobals(globals);
|
||||
viewTab->SetParameters(attribs);
|
||||
viewTab->SetScrolling();
|
||||
xmlNodePtr node = parentNode->xmlChildrenNode;
|
||||
ParseFunctionCalls(node, viewTab);
|
||||
|
||||
subView->AddViewTab(viewTab);
|
||||
}
|
||||
|
||||
void cXmlParser::ParseFunctionCalls(xmlNodePtr node, cTemplatePixmap *pix) {
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
if (!view)
|
||||
return;
|
||||
|
||||
while (node != NULL) {
|
||||
|
||||
if (node->type != XML_ELEMENT_NODE) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!xmlStrcmp(node->name, (const xmlChar *) "loop")) {
|
||||
xmlNodePtr childNode = node->xmlChildrenNode;
|
||||
if (!childNode)
|
||||
continue;
|
||||
xmlAttrPtr attr = node->properties;
|
||||
vector<pair<string, string> > attribs;
|
||||
ParseAttributes(attr, node, attribs);
|
||||
cTemplateLoopFunction *loopFunc = new cTemplateLoopFunction();
|
||||
loopFunc->SetParameters(attribs);
|
||||
ParseLoopFunctionCalls(childNode, loopFunc);
|
||||
pix->AddLoopFunction(loopFunc);
|
||||
node = node->next;
|
||||
} else if (view->ValidFunction((const char*)node->name)) {
|
||||
xmlAttrPtr attr = node->properties;
|
||||
vector<pair<string, string> > attribs;
|
||||
ParseAttributes(attr, node, attribs);
|
||||
pix->AddFunction((const char*)node->name, attribs);
|
||||
node = node->next;
|
||||
} else {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void cXmlParser::ParseLoopFunctionCalls(xmlNodePtr node, cTemplateLoopFunction *loopFunc) {
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
if (!view)
|
||||
return;
|
||||
|
||||
while (node != NULL) {
|
||||
|
||||
if (node->type != XML_ELEMENT_NODE) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
if (view->ValidFunction((const char*)node->name)) {
|
||||
xmlAttrPtr attr = node->properties;
|
||||
vector<pair<string, string> > attribs;
|
||||
ParseAttributes(attr, node, attribs);
|
||||
loopFunc->AddFunction((const char*)node->name, attribs);
|
||||
node = node->next;
|
||||
} else {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool cXmlParser::ParseAttributes(xmlAttrPtr attr, xmlNodePtr node, vector<pair<string, string> > &attribs) {
|
||||
if (attr == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!view)
|
||||
return false;
|
||||
|
||||
while (NULL != attr) {
|
||||
|
||||
string name = (const char*)attr->name;
|
||||
if (!name.compare("debug")) {
|
||||
attribs.push_back(pair<string, string>((const char*)attr->name, "true"));
|
||||
attr = attr->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
xmlChar *value = NULL;
|
||||
value = xmlGetProp(node, attr->name);
|
||||
if (!view->ValidAttribute((const char*)node->name, (const char*)attr->name)) {
|
||||
attr = attr->next;
|
||||
if (value)
|
||||
xmlFree(value);
|
||||
continue;
|
||||
}
|
||||
if (value)
|
||||
attribs.push_back(pair<string, string>((const char*)attr->name, (const char*)value));
|
||||
attr = attr->next;
|
||||
if (value)
|
||||
xmlFree(value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cXmlParser::DebugViewElement(xmlNodePtr node) {
|
||||
xmlAttrPtr attr = node->properties;
|
||||
vector<pair<string, string> > attribs;
|
||||
ParseAttributes(attr, node, attribs);
|
||||
for (vector<pair<string, string> >::iterator it = attribs.begin(); it != attribs.end(); it++) {
|
||||
if (!(it->first).compare("debug"))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
56
libtemplate/xmlparser.h
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef __XMLPARSER_H
|
||||
#define __XMLPARSER_H
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
#include <libxml/xmlerror.h>
|
||||
#include <vdr/plugin.h>
|
||||
|
||||
#include "templateview.h"
|
||||
#include "templateviewlist.h"
|
||||
#include "templateviewtab.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// --- cXmlParser -------------------------------------------------------------
|
||||
|
||||
class cXmlParser {
|
||||
private:
|
||||
cTemplateView *view;
|
||||
cGlobals *globals;
|
||||
xmlParserCtxtPtr ctxt;
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr root;
|
||||
string GetPath(string xmlFile);
|
||||
void ParseGlobalColors(xmlNodePtr node);
|
||||
void InsertColor(string name, string value);
|
||||
void ParseGlobalVariables(xmlNodePtr node);
|
||||
void InsertVariable(string name, string type, string value);
|
||||
void ParseGlobalFonts(xmlNodePtr node);
|
||||
void ParseTranslations(xmlNodePtr node);
|
||||
bool ParseSubView(xmlNodePtr node);
|
||||
void ParseViewElement(const xmlChar * viewElement, xmlNodePtr node, bool debugVE, cTemplateView *subView = NULL);
|
||||
void ParseViewList(xmlNodePtr parentNode, cTemplateView *subView = NULL);
|
||||
void ParseViewTab(xmlNodePtr parentNode, cTemplateView *subView);
|
||||
void ParseFunctionCalls(xmlNodePtr node, cTemplatePixmap *pix);
|
||||
void ParseLoopFunctionCalls(xmlNodePtr node, cTemplateLoopFunction *loopFunc);
|
||||
bool ParseAttributes(xmlAttrPtr attr, xmlNodePtr node, vector<pair<string, string> > &attribs);
|
||||
bool DebugViewElement(xmlNodePtr node);
|
||||
public:
|
||||
cXmlParser(void);
|
||||
virtual ~cXmlParser(void);
|
||||
bool ReadView(cTemplateView *view, string xmlFile);
|
||||
bool ReadGlobals(cGlobals *globals, string xmlFile);
|
||||
bool ParseView(void);
|
||||
bool ParseGlobals(void);
|
||||
void DeleteDocument(void);
|
||||
};
|
||||
|
||||
#endif //__XMLPARSER_H
|
167
services/epgsearch.h
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
Copyright (C) 2004-2007 Christian Wieninger
|
||||
|
||||
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 2
|
||||
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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
|
||||
The author can be reached at cwieninger@gmx.de
|
||||
|
||||
The project's page is at http://winni.vdr-developer.org/epgsearch
|
||||
*/
|
||||
|
||||
#ifndef EPGSEARCHSERVICES_INC
|
||||
#define EPGSEARCHSERVICES_INC
|
||||
|
||||
// Added by Andreas Mair (mail _AT_ andreas _DOT_ vdr-developer _DOT_ org)
|
||||
#define EPGSEARCH_SEARCHRESULTS_SERVICE_STRING_ID "Epgsearch-searchresults-v1.0"
|
||||
#define EPGSEARCH_LASTCONFLICTINFO_SERVICE_STRING_ID "Epgsearch-lastconflictinfo-v1.0"
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vdr/osdbase.h>
|
||||
|
||||
// Data structure for service "Epgsearch-search-v1.0"
|
||||
struct Epgsearch_search_v1_0
|
||||
{
|
||||
// in
|
||||
char* query; // search term
|
||||
int mode; // search mode (0=phrase, 1=and, 2=or, 3=regular expression)
|
||||
int channelNr; // channel number to search in (0=any)
|
||||
bool useTitle; // search in title
|
||||
bool useSubTitle; // search in subtitle
|
||||
bool useDescription; // search in description
|
||||
// out
|
||||
cOsdMenu* pResultMenu; // pointer to the menu of results
|
||||
};
|
||||
|
||||
// Data structure for service "Epgsearch-exttimeredit-v1.0"
|
||||
struct Epgsearch_exttimeredit_v1_0
|
||||
{
|
||||
// in
|
||||
cTimer* timer; // pointer to the timer to edit
|
||||
bool bNew; // flag that indicates, if this is a new timer or an existing one
|
||||
const cEvent* event; // pointer to the event corresponding to this timer (may be NULL)
|
||||
// out
|
||||
cOsdMenu* pTimerMenu; // pointer to the menu of results
|
||||
};
|
||||
|
||||
// Data structure for service "Epgsearch-updatesearchtimers-v1.0"
|
||||
struct Epgsearch_updatesearchtimers_v1_0
|
||||
{
|
||||
// in
|
||||
bool showMessage; // inform via osd when finished?
|
||||
};
|
||||
|
||||
// Data structure for service "Epgsearch-osdmessage-v1.0"
|
||||
struct Epgsearch_osdmessage_v1_0
|
||||
{
|
||||
// in
|
||||
char* message; // the message to display
|
||||
eMessageType type;
|
||||
};
|
||||
|
||||
// Data structure for service "EpgsearchMenu-v1.0"
|
||||
struct EpgSearchMenu_v1_0
|
||||
{
|
||||
// in
|
||||
// out
|
||||
cOsdMenu* Menu; // pointer to the menu
|
||||
};
|
||||
|
||||
// Data structure for service "Epgsearch-lastconflictinfo-v1.0"
|
||||
struct Epgsearch_lastconflictinfo_v1_0
|
||||
{
|
||||
// in
|
||||
// out
|
||||
time_t nextConflict; // next conflict date, 0 if none
|
||||
int relevantConflicts; // number of relevant conflicts
|
||||
int totalConflicts; // total number of conflicts
|
||||
};
|
||||
|
||||
// Data structure for service "Epgsearch-searchresults-v1.0"
|
||||
struct Epgsearch_searchresults_v1_0
|
||||
{
|
||||
// in
|
||||
char* query; // search term
|
||||
int mode; // search mode (0=phrase, 1=and, 2=or, 3=regular expression)
|
||||
int channelNr; // channel number to search in (0=any)
|
||||
bool useTitle; // search in title
|
||||
bool useSubTitle; // search in subtitle
|
||||
bool useDescription; // search in description
|
||||
// out
|
||||
|
||||
class cServiceSearchResult : public cListObject
|
||||
{
|
||||
public:
|
||||
const cEvent* event;
|
||||
cServiceSearchResult(const cEvent* Event) : event(Event) {}
|
||||
};
|
||||
|
||||
cList<cServiceSearchResult>* pResultList; // pointer to the results
|
||||
};
|
||||
|
||||
// Data structure for service "Epgsearch-switchtimer-v1.0"
|
||||
struct Epgsearch_switchtimer_v1_0
|
||||
{
|
||||
// in
|
||||
const cEvent* event;
|
||||
int mode; // mode (0=query existance, 1=add/modify, 2=delete)
|
||||
// in/out
|
||||
int switchMinsBefore;
|
||||
int announceOnly;
|
||||
// out
|
||||
bool success; // result
|
||||
};
|
||||
|
||||
// Data structures for service "Epgsearch-services-v1.0"
|
||||
class cServiceHandler
|
||||
{
|
||||
public:
|
||||
virtual std::list<std::string> SearchTimerList() = 0;
|
||||
// returns a list of search timer entries in the same format as used in epgsearch.conf
|
||||
virtual int AddSearchTimer(const std::string&) = 0;
|
||||
// adds a new search timer and returns its ID (-1 on error)
|
||||
virtual bool ModSearchTimer(const std::string&) = 0;
|
||||
// edits an existing search timer and returns success
|
||||
virtual bool DelSearchTimer(int) = 0;
|
||||
// deletes search timer with given ID and returns success
|
||||
virtual std::list<std::string> QuerySearchTimer(int) = 0;
|
||||
// returns the search result of the searchtimer with given ID in the same format as used in SVDRP command 'QRYS' (->MANUAL)
|
||||
virtual std::list<std::string> QuerySearch(std::string) = 0;
|
||||
// returns the search result of the searchtimer with given settings in the same format as used in SVDRP command 'QRYS' (->MANUAL)
|
||||
virtual std::list<std::string> ExtEPGInfoList() = 0;
|
||||
// returns a list of extended EPG categories in the same format as used in epgsearchcats.conf
|
||||
virtual std::list<std::string> ChanGrpList() = 0;
|
||||
// returns a list of channel groups maintained by epgsearch
|
||||
virtual std::list<std::string> BlackList() = 0;
|
||||
// returns a list of blacklists in the same format as used in epgsearchblacklists.conf
|
||||
virtual std::set<std::string> DirectoryList() = 0;
|
||||
// List of all recording directories used in recordings, timers, search timers or in epgsearchdirs.conf
|
||||
virtual ~cServiceHandler() {}
|
||||
// Read a setup value
|
||||
virtual std::string ReadSetupValue(const std::string& entry) = 0;
|
||||
// Write a setup value
|
||||
virtual bool WriteSetupValue(const std::string& entry, const std::string& value) = 0;
|
||||
};
|
||||
|
||||
struct Epgsearch_services_v1_0
|
||||
{
|
||||
// in/out
|
||||
std::auto_ptr<cServiceHandler> handler;
|
||||
};
|
||||
|
||||
#endif
|
141
services/remotetimers.h
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* remotetimers.h: Public interface of the plugin's services
|
||||
*
|
||||
* Copyright (C) 2008-2011 Frank Schmirler <vdr@schmirler.de>
|
||||
*
|
||||
* This file is part of VDR Plugin remotetimers.
|
||||
*
|
||||
* 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 2
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
* Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
*/
|
||||
|
||||
#ifndef _SERVICE__H
|
||||
#define _SERVICE__H
|
||||
|
||||
#ifndef __TIMERS_H
|
||||
#include <vdr/timers.h>
|
||||
#include <vdr/epg.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If the Data argument is NULL, all service calls return true.
|
||||
* Otherwise the return value indicates success or failure of the service call.
|
||||
*
|
||||
* The service calls are not thread safe and must be called from the VDR main loop.
|
||||
*/
|
||||
|
||||
/*
|
||||
* RemoteTimers::InstantRecording-v1.0
|
||||
* Start an instant recording or pause live TV. VDR needs to be patched to support this.
|
||||
* The service returns false if a local timer should be used. An error occured if true is returned but the out parameters name and fileName are NULL.
|
||||
* Data points to the following structure where pause indicates if it is an instant recording or an attempt to pause live TV.
|
||||
*/
|
||||
|
||||
struct RemoteTimers_InstantRecording_v1_0 {
|
||||
//in
|
||||
const cTimer *timer;
|
||||
bool pause;
|
||||
const cEvent *event;
|
||||
//out
|
||||
cString name;
|
||||
cString fileName;
|
||||
};
|
||||
|
||||
/*
|
||||
* RemoteTimers::RefreshTimers-v1.0
|
||||
* Fetch timer list from remote VDR. You must call this service before you can use one of the service calls below.
|
||||
* Data points to a cString which in case of failure (service call returns false) contains an error message.
|
||||
*/
|
||||
|
||||
//out
|
||||
// cString errorMsg;
|
||||
|
||||
/*
|
||||
* RemoteTimers::ForEach-v1.0
|
||||
* Iterates the list of remote timers.
|
||||
* The service call always returns true.
|
||||
* Data points to a cTimer* which must be NULL to return the first timer. Pass the previously returned timer to get the next one until cTimer* is NULL.
|
||||
*
|
||||
* RemoteTimers::GetTimer-v1.0
|
||||
* Test if the timer exists as either a remote or a local timer.
|
||||
* The service call always returns true.
|
||||
* Data points to a cTimer* which points to the timer you are looking for. If found, cTimer* will point to the timer, otherwise it will be NULL.
|
||||
*/
|
||||
|
||||
//in+out
|
||||
// cTimer* timer;
|
||||
|
||||
/*
|
||||
* RemoteTimers::GetMatch-v1.0
|
||||
* Find the remote or local timer which matches the event best.
|
||||
* The service call always returns true.
|
||||
* Data points to the following structure:
|
||||
*/
|
||||
|
||||
struct RemoteTimers_GetMatch_v1_0 {
|
||||
//in
|
||||
const cEvent *event;
|
||||
//out
|
||||
cTimer *timer;
|
||||
int timerMatch;
|
||||
int timerType;
|
||||
bool isRemote;
|
||||
};
|
||||
|
||||
/*
|
||||
* RemoteTimers::GetTimerByEvent-v1.0
|
||||
* Find the remote or local timer matching the event.
|
||||
* If no timer matches, the service call returns false.
|
||||
* Data points to a RemoteTimers_Event_v1_0 struct.
|
||||
*
|
||||
* RemoteTimers::NewTimerByEvent-v1.0
|
||||
* Add a new timer for an event.
|
||||
* In case of an error, the service call returns false and the structure includes an error message.
|
||||
* Data points to a RemoteTimers_Event_v1_0 struct.
|
||||
*/
|
||||
|
||||
struct RemoteTimers_Event_v1_0 {
|
||||
//in
|
||||
const cEvent *event;
|
||||
//out
|
||||
cTimer *timer;
|
||||
cString errorMsg;
|
||||
};
|
||||
|
||||
/*
|
||||
* RemoteTimers::NewTimer-v1.0
|
||||
* Add a new timer.
|
||||
* In case of an error, the service call returns false and the structure includes an error message.
|
||||
* Data points to a RemoteTimers_Timer_v1_0 struct.
|
||||
*
|
||||
* RemoteTimers::ModTimer-v1.0
|
||||
* Change an existing timer.
|
||||
* In case of an error, the service call returns false and the structure includes an error message.
|
||||
* Data points to a RemoteTimers_Timer_v1_0 struct.
|
||||
*
|
||||
* RemoteTimers::DelTimer-v1.0
|
||||
* Delete an existing timer.
|
||||
* In case of an error, the service call returns false and the structure includes an error message.
|
||||
* Data points to a RemoteTimers_Timer_v1_0 struct.
|
||||
*/
|
||||
|
||||
struct RemoteTimers_Timer_v1_0 {
|
||||
//in+out
|
||||
cTimer *timer;
|
||||
//out
|
||||
cString errorMsg;
|
||||
};
|
||||
|
||||
#endif //_SERVICE__H
|
214
services/scraper2vdr.h
Normal file
@ -0,0 +1,214 @@
|
||||
#ifndef __SCRAPER2VDRSERVICES_H
|
||||
#define __SCRAPER2VDRSERVICES_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <vdr/epg.h>
|
||||
#include <vdr/recording.h>
|
||||
|
||||
enum tvType {
|
||||
tSeries,
|
||||
tMovie,
|
||||
tNone,
|
||||
};
|
||||
|
||||
/*********************************************************************
|
||||
* Helper Structures
|
||||
*********************************************************************/
|
||||
class cTvMedia {
|
||||
public:
|
||||
cTvMedia(void) {
|
||||
path = "";
|
||||
width = height = 0;
|
||||
};
|
||||
std::string path;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
class cEpisode {
|
||||
public:
|
||||
cEpisode(void) {
|
||||
number = 0;
|
||||
season = 0;
|
||||
name = "";
|
||||
firstAired = "";
|
||||
guestStars = "";
|
||||
overview = "";
|
||||
rating = 0.0;
|
||||
};
|
||||
int number;
|
||||
int season;
|
||||
std::string name;
|
||||
std::string firstAired;
|
||||
std::string guestStars;
|
||||
std::string overview;
|
||||
float rating;
|
||||
cTvMedia episodeImage;
|
||||
};
|
||||
|
||||
class cActor {
|
||||
public:
|
||||
cActor(void) {
|
||||
name = "";
|
||||
role = "";
|
||||
};
|
||||
std::string name;
|
||||
std::string role;
|
||||
cTvMedia actorThumb;
|
||||
};
|
||||
|
||||
/*********************************************************************
|
||||
* Data Structures for Service Calls
|
||||
*********************************************************************/
|
||||
|
||||
// Data structure for service "GetEventType"
|
||||
class ScraperGetEventType {
|
||||
public:
|
||||
ScraperGetEventType(void) {
|
||||
event = NULL;
|
||||
recording = NULL;
|
||||
type = tNone;
|
||||
movieId = 0;
|
||||
seriesId = 0;
|
||||
episodeId = 0;
|
||||
};
|
||||
// in
|
||||
const cEvent *event; // check type for this event
|
||||
const cRecording *recording; // or for this recording
|
||||
//out
|
||||
tvType type; //typeSeries or typeMovie
|
||||
int movieId;
|
||||
int seriesId;
|
||||
int episodeId;
|
||||
};
|
||||
|
||||
//Data structure for full series and episode information
|
||||
class cMovie {
|
||||
public:
|
||||
cMovie(void) {
|
||||
title = "";
|
||||
originalTitle = "";
|
||||
tagline = "";
|
||||
overview = "";
|
||||
adult = false;
|
||||
collectionName = "";
|
||||
budget = 0;
|
||||
revenue = 0;
|
||||
genres = "";
|
||||
homepage = "";
|
||||
releaseDate = "";
|
||||
runtime = 0;
|
||||
popularity = 0.0;
|
||||
voteAverage = 0.0;
|
||||
};
|
||||
//IN
|
||||
int movieId; // movieId fetched from ScraperGetEventType
|
||||
//OUT
|
||||
std::string title;
|
||||
std::string originalTitle;
|
||||
std::string tagline;
|
||||
std::string overview;
|
||||
bool adult;
|
||||
std::string collectionName;
|
||||
int budget;
|
||||
int revenue;
|
||||
std::string genres;
|
||||
std::string homepage;
|
||||
std::string releaseDate;
|
||||
int runtime;
|
||||
float popularity;
|
||||
float voteAverage;
|
||||
cTvMedia poster;
|
||||
cTvMedia fanart;
|
||||
cTvMedia collectionPoster;
|
||||
cTvMedia collectionFanart;
|
||||
std::vector<cActor> actors;
|
||||
};
|
||||
|
||||
//Data structure for full series and episode information
|
||||
class cSeries {
|
||||
public:
|
||||
cSeries(void) {
|
||||
seriesId = 0;
|
||||
episodeId = 0;
|
||||
name = "";
|
||||
overview = "";
|
||||
firstAired = "";
|
||||
network = "";
|
||||
genre = "";
|
||||
rating = 0.0;
|
||||
status = "";
|
||||
};
|
||||
//IN
|
||||
int seriesId; // seriesId fetched from ScraperGetEventType
|
||||
int episodeId; // episodeId fetched from ScraperGetEventType
|
||||
//OUT
|
||||
std::string name;
|
||||
std::string overview;
|
||||
std::string firstAired;
|
||||
std::string network;
|
||||
std::string genre;
|
||||
float rating;
|
||||
std::string status;
|
||||
cEpisode episode;
|
||||
std::vector<cActor> actors;
|
||||
std::vector<cTvMedia> posters;
|
||||
std::vector<cTvMedia> banners;
|
||||
std::vector<cTvMedia> fanarts;
|
||||
cTvMedia seasonPoster;
|
||||
};
|
||||
|
||||
// Data structure for service "GetPosterBanner"
|
||||
class ScraperGetPosterBanner {
|
||||
public:
|
||||
ScraperGetPosterBanner(void) {
|
||||
type = tNone;
|
||||
event = NULL;
|
||||
};
|
||||
// in
|
||||
const cEvent *event; // check type for this event
|
||||
//out
|
||||
tvType type; //typeSeries or typeMovie
|
||||
cTvMedia poster;
|
||||
cTvMedia banner;
|
||||
};
|
||||
|
||||
// Data structure for service "GetPosterBannerV2"
|
||||
class ScraperGetPosterBannerV2 {
|
||||
public:
|
||||
ScraperGetPosterBannerV2(void) {
|
||||
type = tNone;
|
||||
event = NULL;
|
||||
recording = NULL;
|
||||
};
|
||||
// in
|
||||
const cEvent *event; // check type for this event
|
||||
const cRecording *recording; // check type for this recording
|
||||
//out
|
||||
tvType type; //typeSeries or typeMovie
|
||||
cTvMedia poster;
|
||||
cTvMedia banner;
|
||||
};
|
||||
|
||||
// Data structure for service "GetPoster"
|
||||
class ScraperGetPoster {
|
||||
public:
|
||||
// in
|
||||
const cEvent *event; // check type for this event
|
||||
const cRecording *recording; // or for this recording
|
||||
//out
|
||||
cTvMedia poster;
|
||||
};
|
||||
|
||||
// Data structure for service "GetPosterThumb"
|
||||
class ScraperGetPosterThumb {
|
||||
public:
|
||||
// in
|
||||
const cEvent *event; // check type for this event
|
||||
const cRecording *recording; // or for this recording
|
||||
//out
|
||||
cTvMedia poster;
|
||||
};
|
||||
|
||||
#endif //__SCRAPER2VDRSERVICES_H
|
73
setup.c
Normal file
@ -0,0 +1,73 @@
|
||||
#include "setup.h"
|
||||
|
||||
cSkinDesignerSetup::cSkinDesignerSetup() {
|
||||
data = config;
|
||||
Setup();
|
||||
}
|
||||
|
||||
cSkinDesignerSetup::~cSkinDesignerSetup() {
|
||||
}
|
||||
|
||||
|
||||
void cSkinDesignerSetup::Setup(void) {
|
||||
int current = Current();
|
||||
Clear();
|
||||
|
||||
Add(new cMenuEditBoolItem(tr("Debug Image Loading"), &data.debugImageLoading));
|
||||
|
||||
Add(new cMenuEditBoolItem(tr("Limit Channel Logo Cache"), &data.limitLogoCache));
|
||||
Add(new cMenuEditIntItem(tr("Number to cache initially (per size)"), &data.numLogosPerSizeInitial, 0, 1000));
|
||||
Add(new cMenuEditIntItem(tr("Number to cache in maximum"), &data.numLogosMax, 0, 1000));
|
||||
|
||||
cString message = cString::sprintf("--------------------- %s ---------------------", tr("Cache Statistics"));
|
||||
Add(new cOsdItem(*message));
|
||||
cList<cOsdItem>::Last()->SetSelectable(false);
|
||||
|
||||
int sizeIconCache = 0;
|
||||
int numIcons = 0;
|
||||
imgCache->GetIconCacheSize(numIcons, sizeIconCache);
|
||||
cString iconCacheInfo = cString::sprintf("%s %d %s - %s %d %s", tr("cached"), numIcons, tr("icons"), tr("size"), sizeIconCache, tr("byte"));
|
||||
Add(new cOsdItem(*iconCacheInfo));
|
||||
cList<cOsdItem>::Last()->SetSelectable(false);
|
||||
|
||||
int sizeLogoCache = 0;
|
||||
int numLogos = 0;
|
||||
imgCache->GetLogoCacheSize(numLogos, sizeLogoCache);
|
||||
cString logoCacheInfo = cString::sprintf("%s %d %s - %s %d %s", tr("cached"), numLogos, tr("logos"), tr("size"), sizeLogoCache, tr("byte"));
|
||||
Add(new cOsdItem(*logoCacheInfo));
|
||||
cList<cOsdItem>::Last()->SetSelectable(false);
|
||||
|
||||
int sizeSkinpartCache = 0;
|
||||
int numSkinparts = 0;
|
||||
imgCache->GetSkinpartsCacheSize(numSkinparts, sizeSkinpartCache);
|
||||
cString skinpartCacheInfo = cString::sprintf("%s %d %s - %s %d %s", tr("cached"), numSkinparts, tr("skinparts"), tr("size"), sizeSkinpartCache, tr("byte"));
|
||||
Add(new cOsdItem(*skinpartCacheInfo));
|
||||
cList<cOsdItem>::Last()->SetSelectable(false);
|
||||
|
||||
SetCurrent(Get(current));
|
||||
Display();
|
||||
}
|
||||
|
||||
eOSState cSkinDesignerSetup::ProcessKey(eKeys Key) {
|
||||
eOSState state = cMenuSetupPage::ProcessKey(Key);
|
||||
switch (state) {
|
||||
case osContinue: {
|
||||
if (NORMALKEY(Key) == kUp || NORMALKEY(Key) == kDown) {
|
||||
cOsdItem* item = Get(Current());
|
||||
if (item)
|
||||
item->ProcessKey(kNone);
|
||||
}
|
||||
break; }
|
||||
default: break;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
void cSkinDesignerSetup::Store(void) {
|
||||
config = data;
|
||||
|
||||
SetupStore("DebugImageLoading", config.debugImageLoading);
|
||||
SetupStore("LimitChannelLogoCache", config.limitLogoCache);
|
||||
SetupStore("NumberLogosInitially", config.numLogosPerSizeInitial);
|
||||
SetupStore("NumberLogosMax", config.numLogosMax);
|
||||
}
|
16
setup.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef __SKINDESIGNER_SETUP_H
|
||||
#define __SKINDESIGNER_SETUP_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
class cSkinDesignerSetup : public cMenuSetupPage {
|
||||
public:
|
||||
cSkinDesignerSetup(void);
|
||||
virtual ~cSkinDesignerSetup();
|
||||
private:
|
||||
cDesignerConfig data;
|
||||
void Setup(void);
|
||||
virtual eOSState ProcessKey(eKeys Key);
|
||||
virtual void Store(void);
|
||||
};
|
||||
#endif //__SKINDESIGNER_SETUP_H
|
165
skindesigner.c
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* skindesigner.c: A plugin for the Video Disk Recorder
|
||||
*
|
||||
* See the README file for copyright information and how to reach the author.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <getopt.h>
|
||||
#include <vdr/plugin.h>
|
||||
#include <vdr/skinlcars.h>
|
||||
|
||||
#define DEFINE_CONFIG 1
|
||||
#include "config.h"
|
||||
#include "designer.h"
|
||||
#include "setup.h"
|
||||
|
||||
|
||||
#if defined(APIVERSNUM) && APIVERSNUM < 20000
|
||||
#error "VDR-2.0.0 API version or greater is required!"
|
||||
#endif
|
||||
|
||||
|
||||
static const char *VERSION = "0.0.1";
|
||||
static const char *DESCRIPTION = "SkinDesigner";
|
||||
static const char *MAINMENUENTRY = "Skin Designer";
|
||||
|
||||
class cPluginSkinDesigner : public cPlugin {
|
||||
private:
|
||||
cSkinDesigner *skinDesigner;
|
||||
public:
|
||||
cPluginSkinDesigner(void);
|
||||
virtual ~cPluginSkinDesigner();
|
||||
virtual const char *Version(void) { return VERSION; }
|
||||
virtual const char *Description(void) { return DESCRIPTION; }
|
||||
virtual const char *CommandLineHelp(void);
|
||||
virtual bool ProcessArgs(int argc, char *argv[]);
|
||||
virtual bool Initialize(void);
|
||||
virtual bool Start(void);
|
||||
virtual void Stop(void);
|
||||
virtual void Housekeeping(void);
|
||||
virtual void MainThreadHook(void);
|
||||
virtual cString Active(void);
|
||||
virtual time_t WakeupTime(void);
|
||||
virtual const char *MainMenuEntry(void) {return NULL;}
|
||||
virtual cOsdObject *MainMenuAction(void);
|
||||
virtual cMenuSetupPage *SetupMenu(void);
|
||||
virtual bool SetupParse(const char *Name, const char *Value);
|
||||
virtual bool Service(const char *Id, void *Data = NULL);
|
||||
virtual const char **SVDRPHelpPages(void);
|
||||
virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode);
|
||||
};
|
||||
|
||||
cPluginSkinDesigner::cPluginSkinDesigner(void) {
|
||||
skinDesigner = NULL;
|
||||
}
|
||||
|
||||
cPluginSkinDesigner::~cPluginSkinDesigner() {
|
||||
}
|
||||
|
||||
const char *cPluginSkinDesigner::CommandLineHelp(void) {
|
||||
return
|
||||
" -s <SKINPATH>, --skinpath=<SKINPATH> Set directory where xml skins are stored\n"
|
||||
" -e <EPGIMAGESPATH>, --epgimages=<IMAGESPATH> Set directory where epgimages are stored\n";
|
||||
}
|
||||
|
||||
bool cPluginSkinDesigner::ProcessArgs(int argc, char *argv[]) {
|
||||
// Implement command line argument processing here if applicable.
|
||||
static const struct option long_options[] = {
|
||||
{ "epgimages", required_argument, NULL, 'e' },
|
||||
{ "skinpath", required_argument, NULL, 's' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
int c;
|
||||
while ((c = getopt_long(argc, argv, "e:s:", long_options, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 'e':
|
||||
config.SetEpgImagePath(cString(optarg));
|
||||
break;
|
||||
case 's':
|
||||
config.SetSkinPath(cString(optarg));
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cPluginSkinDesigner::Initialize(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cPluginSkinDesigner::Start(void) {
|
||||
if (!cOsdProvider::SupportsTrueColor()) {
|
||||
esyslog("skinDesigner: No TrueColor OSD found! Using default Skin LCARS!");
|
||||
return new cSkinLCARS();
|
||||
} else
|
||||
dsyslog("skinDesigner: TrueColor OSD found");
|
||||
skinDesigner = new cSkinDesigner();
|
||||
return skinDesigner;
|
||||
}
|
||||
|
||||
void cPluginSkinDesigner::Stop(void) {
|
||||
delete imgCache;
|
||||
delete fontManager;
|
||||
}
|
||||
|
||||
void cPluginSkinDesigner::Housekeeping(void) {
|
||||
}
|
||||
|
||||
void cPluginSkinDesigner::MainThreadHook(void) {
|
||||
}
|
||||
|
||||
cString cPluginSkinDesigner::Active(void) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
time_t cPluginSkinDesigner::WakeupTime(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cOsdObject *cPluginSkinDesigner::MainMenuAction(void) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cMenuSetupPage *cPluginSkinDesigner::SetupMenu(void) {
|
||||
return new cSkinDesignerSetup();
|
||||
}
|
||||
|
||||
bool cPluginSkinDesigner::SetupParse(const char *Name, const char *Value) {
|
||||
return config.SetupParse(Name, Value);
|
||||
}
|
||||
|
||||
bool cPluginSkinDesigner::Service(const char *Id, void *Data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char **cPluginSkinDesigner::SVDRPHelpPages(void) {
|
||||
static const char *HelpPages[] = {
|
||||
"RELD\n"
|
||||
" force reload of templates and caches",
|
||||
"LSTF\n"
|
||||
" List available Fonts",
|
||||
0
|
||||
};
|
||||
return HelpPages;
|
||||
}
|
||||
|
||||
cString cPluginSkinDesigner::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode) {
|
||||
if (strcasecmp(Command, "RELD") == 0) {
|
||||
if (skinDesigner) {
|
||||
skinDesigner->Reload();
|
||||
return "SKINDESIGNER reload of templates and caches forced.";
|
||||
}
|
||||
} else if (strcasecmp(Command, "LSTF") == 0) {
|
||||
if (skinDesigner) {
|
||||
skinDesigner->ListAvailableFonts();
|
||||
return "SKINDESIGNER available fonts listed in syslog.";
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VDRPLUGINCREATOR(cPluginSkinDesigner); // Don't touch this!
|
BIN
skins/default/graphics/icons/ico_ac3.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
skins/default/graphics/icons/ico_activetimer.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
skins/default/graphics/icons/ico_channelsep.png
Normal file
After Width: | Height: | Size: 958 B |
BIN
skins/default/graphics/icons/ico_crypt_off.png
Normal file
After Width: | Height: | Size: 386 B |
BIN
skins/default/graphics/icons/ico_crypt_on.png
Normal file
After Width: | Height: | Size: 369 B |
BIN
skins/default/graphics/icons/ico_cutted.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
skins/default/graphics/icons/ico_discusage.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
skins/default/graphics/icons/ico_dolby_off.png
Normal file
After Width: | Height: | Size: 458 B |
BIN
skins/default/graphics/icons/ico_dolby_on.png
Normal file
After Width: | Height: | Size: 413 B |
BIN
skins/default/graphics/icons/ico_ff.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
skins/default/graphics/icons/ico_ff_1x.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
skins/default/graphics/icons/ico_ff_2x.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
skins/default/graphics/icons/ico_ff_3x.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
skins/default/graphics/icons/ico_ff_off.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
skins/default/graphics/icons/ico_hd_off.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
skins/default/graphics/icons/ico_hd_on.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
skins/default/graphics/icons/ico_line_off.png
Normal file
After Width: | Height: | Size: 147 B |
BIN
skins/default/graphics/icons/ico_line_on.png
Normal file
After Width: | Height: | Size: 958 B |
BIN
skins/default/graphics/icons/ico_mute.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
skins/default/graphics/icons/ico_pause.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
skins/default/graphics/icons/ico_pause_off.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
skins/default/graphics/icons/ico_play.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
skins/default/graphics/icons/ico_play_off.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
skins/default/graphics/icons/ico_rec_off.png
Normal file
After Width: | Height: | Size: 788 B |
BIN
skins/default/graphics/icons/ico_rec_on.png
Normal file
After Width: | Height: | Size: 1.1 KiB |