diff options
-rw-r--r-- | COPYING | 340 | ||||
-rw-r--r-- | HISTORY | 6 | ||||
-rw-r--r-- | Makefile | 122 | ||||
-rw-r--r-- | Makefile-smaller-VDR1.7.34 | 115 | ||||
-rw-r--r-- | README | 132 | ||||
-rw-r--r-- | channelcolumn.c | 274 | ||||
-rw-r--r-- | channelcolumn.h | 41 | ||||
-rw-r--r-- | config.c | 176 | ||||
-rw-r--r-- | config.h | 67 | ||||
-rw-r--r-- | detailview.c | 186 | ||||
-rw-r--r-- | detailview.h | 39 | ||||
-rw-r--r-- | epggrid.c | 146 | ||||
-rw-r--r-- | epggrid.h | 44 | ||||
-rw-r--r-- | footer.c | 59 | ||||
-rw-r--r-- | footer.h | 23 | ||||
-rw-r--r-- | imageloader.c | 78 | ||||
-rw-r--r-- | imageloader.h | 23 | ||||
-rw-r--r-- | messagebox.c | 114 | ||||
-rw-r--r-- | messagebox.h | 31 | ||||
-rw-r--r-- | osdmanager.c | 52 | ||||
-rwxr-xr-x | po/de_DE.po | 139 | ||||
-rw-r--r-- | setup.c | 209 | ||||
-rw-r--r-- | setup.h | 54 | ||||
-rw-r--r-- | styledpixmap.c | 125 | ||||
-rw-r--r-- | styledpixmap.h | 35 | ||||
-rw-r--r-- | themes/tvguide-darkblue.theme | 28 | ||||
-rw-r--r-- | themes/tvguide-default.theme | 27 | ||||
-rw-r--r-- | timeline.c | 115 | ||||
-rw-r--r-- | timeline.h | 22 | ||||
-rw-r--r-- | timer.c | 106 | ||||
-rw-r--r-- | timer.h | 32 | ||||
-rw-r--r-- | tvguide.c | 194 | ||||
-rw-r--r-- | tvguideosd.c | 541 | ||||
-rw-r--r-- | tvguideosd.h | 45 |
34 files changed, 3740 insertions, 0 deletions
@@ -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. @@ -0,0 +1,6 @@ +VDR Plugin 'tvguide' Revision History +------------------------------------- + +2012-08-12: Version 0.0.1 + +- Initial revision. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7c47228 --- /dev/null +++ b/Makefile @@ -0,0 +1,122 @@ +# +# Makefile for a Video Disk Recorder plugin +# +# $Id$ + +# The official name of this plugin. +# This name will be used in the '-P...' option of VDR to load the plugin. +# By default the main source file also carries this name. +# +PLUGIN = tvguide + +### 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 = $(DESTDIR)$(call PKGCFG,libdir) +LOCDIR = $(DESTDIR)$(call PKGCFG,locdir) +PLGCFG = $(call PKGCFG,plgcfg) +CONFDIR= $(DESTDIR)$(call PKGCFG,configdir) +TMPDIR ?= /tmp + +### The compiler options: +export CFLAGS = $(call PKGCFG,cflags) +export CXXFLAGS = $(call PKGCFG,cxxflags) + +### Allow user defined options to overwrite defaults: +-include $(PLGCFG) + +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 (add further entries here): + +INCLUDES += +INCLUDES += -I/usr/include/ImageMagick + +DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' + +### The object files (add further files here): + +OBJS = $(PLUGIN).o + +### The main target: + +all: $(SOFILE) i18n + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< + +### Dependencies: + +MAKEDEP = $(CXX) -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Makefile + @$(MAKEDEP) $(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 $(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): $(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) -lMagick++ -o $@ + +install-lib: $(SOFILE) + install -D $^ $(LIBDIR)/$^.$(APIVERSION) + +install-themes: + @mkdir -p $(CONFDIR)/themes + cp themes/* $(CONFDIR)/themes + +install: install-lib install-i18n install-themes + +dist: $(I18Npo) clean + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @mkdir $(TMPDIR)/$(ARCHIVE) + @cp -a * $(TMPDIR)/$(ARCHIVE) + @tar czf $(PACKAGE).tgz -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* *~ diff --git a/Makefile-smaller-VDR1.7.34 b/Makefile-smaller-VDR1.7.34 new file mode 100644 index 0000000..49b84cc --- /dev/null +++ b/Makefile-smaller-VDR1.7.34 @@ -0,0 +1,115 @@ +# +# Makefile for a Video Disk Recorder plugin +# +# $Id$ + +# The official name of this plugin. +# This name will be used in the '-P...' option of VDR to load the plugin. +# By default the main source file also carries this name. +# IMPORTANT: the presence of this macro is important for the Make.config +# file. So it must be defined, even if it is not used here! +# +PLUGIN = tvguide + +### 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 C++ compiler and options: + +CXX ?= g++ +CXXFLAGS ?= -g -O3 -Wall -Woverloaded-virtual -Wno-parentheses + +### The directory environment: + +VDRDIR ?= ../../.. +LIBDIR ?= ../../lib +TMPDIR ?= /tmp + +### Make sure that necessary options are included: + +include $(VDRDIR)/Make.global + +### Allow user defined options to overwrite defaults: + +-include $(VDRDIR)/Make.config + +### The version number of VDR's plugin API (taken from VDR's "config.h"): + +APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/config.h) + +### The name of the distribution archive: + +ARCHIVE = $(PLUGIN)-$(VERSION) +PACKAGE = vdr-$(ARCHIVE) + +### Includes and Defines (add further entries here): + +INCLUDES += -I$(VDRDIR)/include +INCLUDES += -I/usr/include/ImageMagick + +DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' + +### The object files (add further files here): + +OBJS = $(PLUGIN).o + +### The main target: + +all: libvdr-$(PLUGIN).so i18n + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< + +### Dependencies: + +MAKEDEP = $(CXX) -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + +### Internationalization (I18N): + +PODIR = po +LOCALEDIR = $(VDRDIR)/locale +I18Npo = $(wildcard $(PODIR)/*.po) +I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(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 $@ $^ + +%.po: $(I18Npot) + msgmerge -U --no-wrap --no-location --backup=none -q $@ $< + @touch $@ + +$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo + @mkdir -p $(dir $@) + cp $< $@ + +.PHONY: i18n +i18n: $(I18Nmsgs) $(I18Npot) + +### Targets: + +libvdr-$(PLUGIN).so: $(OBJS) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -lMagick++ -o $@ + @cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION) + +dist: $(I18Npo) clean + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @mkdir $(TMPDIR)/$(ARCHIVE) + @cp -a * $(TMPDIR)/$(ARCHIVE) + @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE) + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @echo Distribution package created as $(PACKAGE).tgz + +clean: + @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ $(PODIR)/*.mo $(PODIR)/*.pot @@ -0,0 +1,132 @@ +This is a "plugin" for the Video Disk Recorder (VDR). + +Written by: Louis Braun <louis DOT braun AT gmx DOT de> + +Project's homepage: URL + +Latest version available at: URL + +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. + +Requirements +------------ + +- VDR version >= 1.7.17 (TrueColor OSD is mandatorily needed) + +- Installed ImageMagick for showing png/jpg Channel Logos and EPG Images + + +Description +----------- + +"TvGuide" is a highly customizable 2D EPG viewer plugin. + +Installation +------------ + +After "normal" Plugin installation copy the themes from + +/put/your/path/here/VDR/PLUGINS/src/tvguide/themes/ + +to + +VDRCONF/themes/ + +Options +------- + +-l path, --logodir=path + Path to the logos (Default: <vdrconfdir>/plugins/tvguide/channellogos/). + +-i path, --epgimages=path + Path to the epgimages (Default: <vdrconfdir>/plugins/tvguide/epgimages/). + + +Usage +----- + +Remote Control Keys: + +Up/Down/Left/Right: Navigation in the EPG grid +Ok: Detailed EPG View of the selected grid + 2nd Ok closes the detailed view +Red: Set recording timer for the currently selected grid +Green / Yellow: Jump (default) five channels back / forward +Blue: Switch to currently selected channel +1 / 3: Big jump (default 3h) back / forward in time +4 / 6: huge jump (default 24h) back / forward in time +7 / 9: jump to previous / next prime time (8pm) +Exit: closes plugin + + +Setup Options +------------- + +* General: + +- Number of Channels / Columns: + Number of columns per screen (max. 8) + Keep in mind that the True Color OSD displays 64 Pixmaps in maximum, and each EPG + entry is a dedicated Pixmap. So if this value is too large, maybe not all EPG + information is shown on the screen. + +- Channel Jump (Keys Green / Yellow): + Number of channels to jump back / forward, counted from the currently selected + channel (channel to which the selected EPG entry belongs) + +- Time to display vertically in minutes + With this value the number of minutes per screen is determinated. The value is + an approximately value, because rounded values are used during calculation. + int((OSD Height - Header Height - Footer Height) / value) + --> Number of Pixel for one minute + +- Big Step (Keys 1 / 3) in hours + Hours to jump vertically with keys 1 / 3 + +- Huge Step (Keys 4 / 6) in hours + Hours to jump vertically with keys 4 / 6 + +- Time Format (12h/24h) + Switching between 12h and 24h time format + +* Screen Layout: + +- Theme + Used Theme, theme files have to be placed accordingly + +- Width of left Time Column + Width of almost left column in Pixel + +- Height of Header (Channel Logos) + Height of header row in Pixel + +- Height of Footer (Buttons) + Height of footer with color buttons in Pixel + +- Show Channel Logos + show / hide channel logos, if logos are shown: + - Logo Extension + jpg / png + - Logo width + in Pixel + - Logo height + in Pixel + +- Show EPG Images + show / hide EPG images, if images are shown: + - EPG Image width + in Pixel + - EPG Image height + in Pixel + +* Fonts and Fontsizes: + +- Font: + Used Font, all Fonts installed on your system are shown +- various font sizes: + Size in Pixel used for described purpose + diff --git a/channelcolumn.c b/channelcolumn.c new file mode 100644 index 0000000..de5962b --- /dev/null +++ b/channelcolumn.c @@ -0,0 +1,274 @@ +#include "channelcolumn.h" + +cChannelColumn::cChannelColumn(int num, cChannel *channel, cMyTime *myTime) { + this->channel = channel; + this->num = num; + this->myTime = myTime; + hasTimer = channel->HasTimer(); +} + +cChannelColumn::~cChannelColumn(void) { + grids.Clear(); +} + +void cChannelColumn::clearGrids() { + grids.Clear(); +} + +void cChannelColumn::createHeader() { + color = theme.Color(clrHeader); + colorBlending = theme.Color(clrHeaderBlending); + caller = cString::sprintf("channelcolumn %s", channel->Name()); + pixmap = osdManager.requestPixmap(2, cRect(tvguideConfig.timeColWidth + num*tvguideConfig.colWidth, 0, tvguideConfig.colWidth, tvguideConfig.headerHeight), + cRect::Null, *caller); + if (!pixmap) { + return; + } + drawBackground(); + cTextWrapper tw; + cString headerText = cString::sprintf("%d - %s", channel->Number(), channel->Name()); + tw.Set(*headerText, tvguideConfig.FontHeader, tvguideConfig.colWidth - 8); + int lines = tw.Lines(); + int lineHeight = tvguideConfig.FontHeader->Height(); + int yStart = (tvguideConfig.headerHeight - lines*lineHeight)/2 + 8; + + if (!tvguideConfig.hideChannelLogos) { + cImageLoader imgLoader; + if (imgLoader.LoadLogo(channel->Name())) { + cImage logo = imgLoader.GetImage(); + int logoX = (tvguideConfig.colWidth - tvguideConfig.logoWidth)/2; + pixmap->DrawImage(cPoint(logoX, 5), logo); + } + yStart = tvguideConfig.logoHeight + 8; + } + for (int i=0; i<lines; i++) { + int textWidth = tvguideConfig.FontHeader->Width(tw.GetLine(i)); + int xText = (tvguideConfig.colWidth - textWidth) / 2; + if (xText < 0) + xText = 0; + pixmap->DrawText(cPoint(xText, yStart + i*lineHeight), tw.GetLine(i), theme.Color(clrFontHeader), clrTransparent, tvguideConfig.FontHeader); + } + drawBorder(); +} + +void cChannelColumn::drawHeader() { + pixmap->SetViewPort(cRect(tvguideConfig.timeColWidth + num*tvguideConfig.colWidth, 0, tvguideConfig.colWidth, tvguideConfig.headerHeight)); +} + +bool cChannelColumn::readGrids() { + schedules = cSchedules::Schedules(schedulesLock); + const cSchedule *Schedule = NULL; + Schedule = schedules->GetSchedule(channel); + if (!Schedule) { + return false; + } + bool eventFound = false; + const cEvent *event = Schedule->GetEventAround(myTime->GetStart()); + if (event != NULL) { + eventFound = true; + } else { + for (int i=1; i<6; i++) { + event = Schedule->GetEventAround(myTime->GetStart()+i*5*60); + if (event) { + eventFound = true; + break; + } + } + } + if (eventFound) { + bool col = true; + for (; event; event = Schedule->Events()->Next(event)) { + cEpgGrid *grid = new cEpgGrid(this, event); + grid->setText(); + grid->SetColor(col); + col = !col; + grids.Add(grid); + if (event->EndTime() > myTime->GetStop()) { + break; + } + } + return true; + } else { + return false; + } + +} + +void cChannelColumn::drawGrids() { + for (cEpgGrid *grid = grids.First(); grid; grid = grids.Next(grid)) { + grid->SetViewportHeight(); + grid->PositionPixmap(); + grid->Draw(); + } +} + +int cChannelColumn::getX() { + return tvguideConfig.timeColWidth + num*tvguideConfig.colWidth; +} + +cEpgGrid * cChannelColumn::getActive() { + cMyTime t; + t.Now(); + for (cEpgGrid *grid = grids.First(); grid; grid = grids.Next(grid)) { + if (grid->isActiveInitial(t.Get())) + return grid; + } + return grids.First(); +} + +cEpgGrid * cChannelColumn::getNext(cEpgGrid *activeGrid) { + if (activeGrid == NULL) + return NULL; + cEpgGrid *next = grids.Next(activeGrid); + if (next) + return next; + return NULL; +} + +cEpgGrid * cChannelColumn::getPrev(cEpgGrid *activeGrid) { + if (activeGrid == NULL) + return NULL; + cEpgGrid *prev = grids.Prev(activeGrid); + if (prev) + return prev; + return NULL; +} + +cEpgGrid * cChannelColumn::getNeighbor(cEpgGrid *activeGrid) { + if (!activeGrid) + return NULL; + cEpgGrid *neighbor = NULL; + int overlap = 0; + int overlapNew = 0; + cEpgGrid *grid = NULL; + grid = grids.First(); + if (grid) { + for (; grid; grid = grids.Next(grid)) { + if ( (grid->StartTime() == activeGrid->StartTime()) ) { + neighbor = grid; + break; + } + overlapNew = activeGrid->calcOverlap(grid); + if (overlapNew > overlap) { + neighbor = grid; + overlap = overlapNew; + } + } + } + if (!neighbor) + neighbor = grids.First(); + return neighbor; +} + +void cChannelColumn::AddNewGridsAtStart() { + cEpgGrid *firstGrid = NULL; + firstGrid = grids.First(); + if (firstGrid == NULL) { + //no epg, completely new. + schedules = cSchedules::Schedules(schedulesLock); + const cSchedule *Schedule = NULL; + Schedule = schedules->GetSchedule(channel); + if (!Schedule) + return; + const cEvent *event = Schedule->GetEventAround(myTime->GetStart()); + if (!event) + return; + cEpgGrid *grid = new cEpgGrid(this, event); + grid->setText(); + grid->SetColor(true); + grids.Ins(grid, grids.First()); + return; + } else { + //if first event is long enough, nothing to do. + if (firstGrid->StartTime() <= myTime->GetStart()) { + return; + } + //if not, i have to add new ones to the list + schedules = cSchedules::Schedules(schedulesLock); + const cSchedule *Schedule = NULL; + Schedule = schedules->GetSchedule(channel); + if (!Schedule) + return; + bool col = !(firstGrid->IsColor1()); + for (const cEvent *event = Schedule->GetEventAround(firstGrid->StartTime()-60); event; event = Schedule->Events()->Prev(event)) { + if (!event) + return; + cEpgGrid *grid = new cEpgGrid(this, event); + grid->setText(); + grid->SetColor(col); + col = !col; + grids.Ins(grid, firstGrid); + firstGrid = grid; + if (event->StartTime() <= myTime->GetStart()) { + break; + } + } + } +} + +void cChannelColumn::AddNewGridsAtEnd() { + cEpgGrid *lastGrid = NULL; + lastGrid = grids.Last(); + if (lastGrid == NULL) + return; + //if last event is long enough, nothing to do. + if (lastGrid->EndTime() > myTime->GetStop()) { + return; + } + //if not, i have to add new ones to the list + schedules = cSchedules::Schedules(schedulesLock); + const cSchedule *Schedule = NULL; + Schedule = schedules->GetSchedule(channel); + if (!Schedule) + return; + bool col = !(lastGrid->IsColor1()); + for (const cEvent *event = Schedule->GetEventAround(lastGrid->EndTime()+60); event; event = Schedule->Events()->Next(event)) { + if (!event) + return; + cEpgGrid *grid = new cEpgGrid(this, event); + grid->setText(); + grid->SetColor(col); + col = !col; + grids.Add(grid); + if (event->EndTime() > myTime->GetStop()) { + break; + } + } +} + +void cChannelColumn::ClearOutdatedStart() { + bool goOn = true; + cEpgGrid *firstGrid = NULL; + while (goOn) { + firstGrid = grids.First(); + if ((firstGrid != NULL)&&(firstGrid->EndTime() < myTime->GetStart())) { + grids.Del(firstGrid); + firstGrid = NULL; + } else { + goOn = false; + } + } +} + +void cChannelColumn::ClearOutdatedEnd() { + bool goOn = true; + cEpgGrid *lastGrid = NULL; + while (goOn) { + lastGrid = grids.Last(); + if ((lastGrid != NULL)&&(lastGrid->StartTime() > myTime->GetStop())) { + grids.Del(lastGrid); + lastGrid = NULL; + } else { + goOn = false; + } + } +} + +void cChannelColumn::dumpGrids() { + esyslog("------Channel %s ---------", channel->Name()); + + for (cEpgGrid *grid = grids.First(); grid; grid = grids.Next(grid)) { + grid->debug(); + } + +} diff --git a/channelcolumn.h b/channelcolumn.h new file mode 100644 index 0000000..28064d2 --- /dev/null +++ b/channelcolumn.h @@ -0,0 +1,41 @@ +#ifndef __TVGUIDE_CHANNELCOLUMN_H +#define __TVGUIDE_CHANNELCOLUMN_H + +class cEpgGrid; +// --- cChannelColumn ------------------------------------------------------------- + +class cChannelColumn : public cListObject, public cStyledPixmap { +friend class cEpgGrid; +private: + cMyTime *myTime; + int num; + cChannel *channel; + cList<cEpgGrid> grids; + cSchedulesLock schedulesLock; + const cSchedules *schedules; + bool hasTimer; +public: + cChannelColumn(int num, cChannel *channel, cMyTime *myTime); + virtual ~cChannelColumn(void); + void createHeader(); + void drawHeader(); + bool readGrids(); + void drawGrids(); + int getX(); + cChannel * getChannel() {return channel;} + cEpgGrid * getActive(); + cEpgGrid * getNext(cEpgGrid *activeGrid); + cEpgGrid * getPrev(cEpgGrid *activeGrid); + cEpgGrid * getNeighbor(cEpgGrid *activeGrid); + void AddNewGridsAtStart(); + void AddNewGridsAtEnd(); + void ClearOutdatedStart(); + void ClearOutdatedEnd(); + int GetNum() {return num;}; + void SetNum(int num) {this->num = num;}; + void setTimer() {hasTimer = true;}; + void clearGrids(); + void dumpGrids(); +}; + +#endif //__TVGUIDE_CHANNELCOLUMN_H
\ No newline at end of file diff --git a/config.c b/config.c new file mode 100644 index 0000000..229f8aa --- /dev/null +++ b/config.c @@ -0,0 +1,176 @@ +#include "config.h"
+
+enum {
+ e12Hours,
+ e24Hours
+};
+
+cTvguideConfig::cTvguideConfig() {
+ osdWidth = 0;
+ osdHeight = 0;
+ colWidth = 0;
+ channelCols = 5;
+ displayTime = 160;
+ minuteHeight = 0;
+ timeColWidth = 120;
+ headerHeight = 120;
+ footerHeight = 80;
+ stepMinutes = 30;
+ bigStepHours = 3;
+ hugeStepHours = 24;
+ jumpChannels = 5;
+ hideChannelLogos = 0;
+ logoWidth = 130;
+ logoHeight = 73;
+ logoExtension = 0;
+ hideEpgImages = 0;
+ epgImageWidth = 315;
+ epgImageHeight = 240;
+ fontIndex = 0;
+ fontNameDefault = "VDRSymbols Sans:Book";
+ fontHeaderSize = 33;
+ fontGridSize = 27;
+ fontGridSmallSize = 24;
+ fontTimeLineWeekdaySize = 40;
+ fontTimeLineDateSize = 33;
+ fontTimeLineTimeSize = 0;
+ fontTimeLineTimeSizeDef12 = 24;
+ fontTimeLineTimeSizeDef24 = 33;
+ fontButtonSize = 33;
+ fontDetailViewSize = 33;
+ fontDetailHeaderSize = 40;
+ fontMessageBoxSize = 33;
+ fontMessageBoxLargeSize = 40;
+
+
+ FontHeader = NULL;
+ FontGrid = NULL;
+ FontGridSmall = NULL;
+ FontTimeLineWeekday = NULL;
+ FontTimeLineDate = NULL;
+ FontTimeLineTime = NULL;
+ FontButton = NULL;
+ FontDetailView = NULL;
+ FontDetailHeader = NULL;
+ FontMessageBox = NULL;
+ FontMessageBoxLarge = NULL;
+
+ timeFormat = 1;
+ themeIndex = 0;
+ useBlending = 1;
+ roundedCorners = 0;
+}
+
+cTvguideConfig::~cTvguideConfig() {
+ delete FontHeader;
+ delete FontGrid;
+ delete FontGridSmall;
+ delete FontTimeLineWeekday;
+ delete FontTimeLineDate;
+ delete FontTimeLineTime;
+ delete FontButton;
+ delete FontDetailView;
+ delete FontDetailHeader;
+ delete FontMessageBox;
+ delete FontMessageBoxLarge;
+}
+
+void cTvguideConfig::setDynamicValues(int width, int height) {
+ osdWidth = width;
+ osdHeight = height;
+ colWidth = (osdWidth - timeColWidth) / channelCols;
+ minuteHeight = (osdHeight - headerHeight - footerHeight) / displayTime;
+
+ if (!fontTimeLineTimeSize) {
+ if (timeFormat == e12Hours) {
+ fontTimeLineTimeSize = fontTimeLineTimeSizeDef12;
+ } else if (timeFormat == e24Hours) {
+ fontTimeLineTimeSize = fontTimeLineTimeSizeDef24;
+ }
+ } else if ((fontTimeLineTimeSize == fontTimeLineTimeSizeDef12) && (timeFormat == e24Hours)) {
+ fontTimeLineTimeSize = fontTimeLineTimeSizeDef24;
+ } else if ((fontTimeLineTimeSize == fontTimeLineTimeSizeDef24) && (timeFormat == e12Hours)) {
+ fontTimeLineTimeSize = fontTimeLineTimeSizeDef12;
+ }
+ cString fontname;
+ if (fontIndex == 0) {
+ fontname = fontNameDefault;
+ } else {
+ cStringList availableFonts;
+ cFont::GetAvailableFontNames(&availableFonts);
+ if (availableFonts[fontIndex-1]) {
+ fontname = availableFonts[fontIndex-1];
+ } else
+ fontname = fontNameDefault;
+ }
+ cFont *test = NULL;
+ test = cFont::CreateFont(*fontname, fontHeaderSize);
+ if (!test) {
+ fontname = DefaultFontSml;
+ }
+ delete test;
+ FontHeader = cFont::CreateFont(*fontname, fontHeaderSize);
+ FontGrid = cFont::CreateFont(*fontname, fontGridSize);
+ FontGridSmall = cFont::CreateFont(*fontname, fontGridSmallSize);
+ FontTimeLineWeekday = cFont::CreateFont(*fontname, fontTimeLineWeekdaySize);
+ FontTimeLineDate = cFont::CreateFont(*fontname, fontTimeLineDateSize);
+ FontTimeLineTime = cFont::CreateFont(*fontname, fontTimeLineTimeSize);
+ FontButton = cFont::CreateFont(*fontname, fontButtonSize);
+ FontDetailView = cFont::CreateFont(*fontname, fontDetailViewSize);
+ FontDetailHeader = cFont::CreateFont(*fontname, fontDetailHeaderSize);
+ FontMessageBox = cFont::CreateFont(*fontname, fontMessageBoxSize);
+ FontMessageBoxLarge = cFont::CreateFont(*fontname, fontMessageBoxLargeSize);
+}
+
+void cTvguideConfig::SetLogoPath(cString path) {
+ logoPath = path;
+}
+
+void cTvguideConfig::SetImagesPath(cString path) {
+ epgImagePath = path;
+}
+
+void cTvguideConfig::loadTheme() {
+ cThemes themes;
+ themes.Load(*cString("tvguide"));
+ const char *FileName = themes.FileName(themeIndex);
+ if (access(FileName, F_OK) == 0) {
+ ::theme.Load(FileName);
+ }
+}
+
+bool cTvguideConfig::SetupParse(const char *Name, const char *Value) {
+ if (strcmp(Name, "timeFormat") == 0) timeFormat = atoi(Value);
+ else if (strcmp(Name, "themeIndex") == 0) themeIndex = atoi(Value);
+ else if (strcmp(Name, "useBlending") == 0) useBlending = atoi(Value);
+ else if (strcmp(Name, "roundedCorners") == 0) roundedCorners = atoi(Value);
+ else if (strcmp(Name, "channelCols") == 0) channelCols = atoi(Value);
+ else if (strcmp(Name, "displayTime") == 0) displayTime = atoi(Value);
+ else if (strcmp(Name, "hideChannelLogos") == 0) hideChannelLogos = atoi(Value);
+ else if (strcmp(Name, "logoExtension") == 0) logoExtension = atoi(Value);
+ else if (strcmp(Name, "logoWidth") == 0) logoWidth = atoi(Value);
+ else if (strcmp(Name, "logoHeight") == 0) logoHeight = atoi(Value);
+ else if (strcmp(Name, "bigStepHours") == 0) bigStepHours = atoi(Value);
+ else if (strcmp(Name, "hugeStepHours") == 0) hugeStepHours = atoi(Value);
+ else if (strcmp(Name, "jumpChannels") == 0) jumpChannels = atoi(Value);
+ else if (strcmp(Name, "hideEpgImages") == 0) hideEpgImages = atoi(Value);
+ else if (strcmp(Name, "epgImageWidth") == 0) epgImageWidth = atoi(Value);
+ else if (strcmp(Name, "epgImageHeight") == 0) epgImageHeight = atoi(Value);
+ else if (strcmp(Name, "timeColWidth") == 0) timeColWidth = atoi(Value);
+ else if (strcmp(Name, "headerHeight") == 0) headerHeight = atoi(Value);
+ else if (strcmp(Name, "footerHeight") == 0) footerHeight = atoi(Value);
+ else if (strcmp(Name, "fontIndex") == 0) fontIndex = atoi(Value);
+ else if (strcmp(Name, "fontHeaderSize") == 0) fontHeaderSize = atoi(Value);
+ else if (strcmp(Name, "fontGridSize") == 0) fontGridSize = atoi(Value);
+ else if (strcmp(Name, "fontGridSmallSize") == 0) fontGridSmallSize = atoi(Value);
+ else if (strcmp(Name, "fontTimeLineWeekdaySize") == 0) fontTimeLineWeekdaySize = atoi(Value);
+ else if (strcmp(Name, "fontTimeLineDateSize") == 0) fontTimeLineDateSize = atoi(Value);
+ else if (strcmp(Name, "fontTimeLineTimeSize") == 0) fontTimeLineTimeSize = atoi(Value);
+ else if (strcmp(Name, "fontButtonSize") == 0) fontButtonSize = atoi(Value);
+ else if (strcmp(Name, "fontDetailViewSize") == 0) fontDetailViewSize = atoi(Value);
+ else if (strcmp(Name, "fontDetailHeaderSize") == 0) fontDetailHeaderSize = atoi(Value);
+ else if (strcmp(Name, "fontMessageBoxSize") == 0) fontMessageBoxSize = atoi(Value);
+ else if (strcmp(Name, "fontMessageBoxLargeSize") == 0) fontMessageBoxLargeSize = atoi(Value);
+ else return false;
+ return true;
+}
\ No newline at end of file diff --git a/config.h b/config.h new file mode 100644 index 0000000..0e184c8 --- /dev/null +++ b/config.h @@ -0,0 +1,67 @@ +#ifndef __TVGUIDE_CONFIG_H
+#define __TVGUIDE_CONFIG_H
+
+class cTvguideConfig {
+ public:
+ cTvguideConfig();
+ ~cTvguideConfig();
+ void SetLogoPath(cString path);
+ void SetImagesPath(cString path);
+ int osdWidth;
+ int osdHeight;
+ int colWidth;
+ int channelCols;
+ int displayTime;
+ int minuteHeight;
+ int timeColWidth;
+ int headerHeight;
+ int footerHeight;
+ int stepMinutes;
+ int bigStepHours;
+ int hugeStepHours;
+ int jumpChannels;
+ int hideChannelLogos;
+ int logoWidth;
+ int logoHeight;
+ cString logoPath;
+ int logoExtension;
+ int hideEpgImages;
+ int epgImageWidth;
+ int epgImageHeight;
+ cString epgImagePath;
+ int fontIndex;
+ const char *fontNameDefault;
+ int fontHeaderSize;
+ int fontGridSize;
+ int fontGridSmallSize;
+ int fontTimeLineWeekdaySize;
+ int fontTimeLineDateSize;
+ int fontTimeLineTimeSize;
+ int fontTimeLineTimeSizeDef12;
+ int fontTimeLineTimeSizeDef24;
+ int fontButtonSize;
+ int fontDetailViewSize;
+ int fontDetailHeaderSize;
+ int fontMessageBoxSize;
+ int fontMessageBoxLargeSize;
+ const cFont *FontHeader;
+ const cFont *FontGrid;
+ const cFont *FontGridSmall;
+ const cFont *FontTimeLineWeekday;
+ const cFont *FontTimeLineDate;
+ const cFont *FontTimeLineTime;
+ const cFont *FontButton;
+ const cFont *FontDetailView;
+ const cFont *FontDetailHeader;
+ const cFont *FontMessageBox;
+ const cFont *FontMessageBoxLarge;
+ int timeFormat;
+ int themeIndex;
+ int useBlending;
+ int roundedCorners;
+ void setDynamicValues(int width, int height);
+ bool SetupParse(const char *Name, const char *Value);
+ void loadTheme();
+};
+
+#endif //__TVGUIDE_CONFIG_H
\ No newline at end of file diff --git a/detailview.c b/detailview.c new file mode 100644 index 0000000..2c791e4 --- /dev/null +++ b/detailview.c @@ -0,0 +1,186 @@ +#include "detailview.h" + +cDetailView::cDetailView(cEpgGrid *grid) { + this->grid = grid; + this->event = grid->GetEvent(); + imgScrollBar = NULL; + FrameTime = 40; // ms + FadeTime = 500; // ms + borderWidth = 100; //px + headerHeight = max (80 + tvguideConfig.logoHeight + 3 * tvguideConfig.FontDetailHeader->Height(), // border + logo + 3 Lines + 80 + tvguideConfig.epgImageHeight); + description.Set(event->Description(), tvguideConfig.FontDetailView, tvguideConfig.osdWidth-2*borderWidth - 50 - 40); + contentScrollable = setContentDrawportHeight(); + createPixmaps(); +} + +cDetailView::~cDetailView(void){ + delete header; + osdManager.releasePixmap(content); + osdManager.releasePixmap(scrollBar); + osdManager.releasePixmap(footer); + delete imgScrollBar; +} + +bool cDetailView::setContentDrawportHeight() { + int linesContent = description.Lines() + 1; + heightContent = linesContent * tvguideConfig.FontDetailView->Height(); + if (heightContent > (tvguideConfig.osdHeight - 2 * borderWidth - headerHeight)) + return true; + else + return false; +} + +void cDetailView::createPixmaps() { + int scrollBarWidth = 50; + + header = new cStyledPixmap(osdManager.requestPixmap(5, cRect(borderWidth, borderWidth, tvguideConfig.osdWidth - 2*borderWidth, headerHeight), cRect::Null, "detailViewHeader"), "detailViewHeader"); + header->SetAlpha(0); + header->setColor(theme.Color(clrHeader), theme.Color(clrHeaderBlending)); + content = osdManager.requestPixmap(5, cRect(borderWidth, borderWidth + headerHeight, tvguideConfig.osdWidth - 2*borderWidth - scrollBarWidth, tvguideConfig.osdHeight-2*borderWidth-headerHeight), + cRect(0,0, tvguideConfig.osdWidth - 2*borderWidth - scrollBarWidth, max(heightContent, tvguideConfig.osdHeight-2*borderWidth-headerHeight))); + content->SetAlpha(0); + header->setColor(theme.Color(clrHeader), theme.Color(clrHeaderBlending)); + + scrollBar = osdManager.requestPixmap(5, cRect(tvguideConfig.osdWidth-borderWidth-scrollBarWidth, borderWidth + headerHeight, scrollBarWidth, tvguideConfig.osdHeight-2*borderWidth-headerHeight)); + scrollBar->SetAlpha(0); + + footer = osdManager.requestPixmap(5, cRect(borderWidth, borderWidth + headerHeight + content->ViewPort().Height(), tvguideConfig.osdWidth - 2*borderWidth, 3)); + footer->SetAlpha(0); + footer->Fill(clrWhite); +} + +void cDetailView::drawHeader() { + header->drawBackground(); + header->drawBoldBorder(); + + int lineHeight = tvguideConfig.FontDetailHeader->Height(); + int offset = 30; + cImageLoader imgLoader; + if (tvguideConfig.hideChannelLogos) { + header->DrawText(cPoint(20, offset + 10), grid->column->getChannel()->Name(), theme.Color(clrFont), clrTransparent, tvguideConfig.FontDetailHeader); + offset += lineHeight + 10; + } else { + if (imgLoader.LoadLogo(grid->column->getChannel()->Name())) { + cImage logo = imgLoader.GetImage(); + header->DrawImage(cPoint(20, 20), logo); + } + offset += tvguideConfig.logoHeight; + } + + if (!tvguideConfig.hideEpgImages) { + if (imgLoader.LoadEPGImage(event->EventID())) { + cImage epgImage = imgLoader.GetImage(); + int epgImageX = header->Width() - 30 - tvguideConfig.epgImageWidth; + int epgImageY = (header->Height() - 10 - tvguideConfig.epgImageHeight) / 2; + header->DrawRectangle(cRect(epgImageX-2, epgImageY-2, tvguideConfig.epgImageWidth + 4, tvguideConfig.epgImageHeight + 4), theme.Color(clrBorder)); + header->DrawImage(cPoint(epgImageX, epgImageY), epgImage); + } + } + + header->DrawText(cPoint(20, offset), event->Title(), theme.Color(clrFont), clrTransparent, tvguideConfig.FontDetailHeader); + cString datetime = cString::sprintf("%s, %s - %s (%d min)", *event->GetDateString(), *event->GetTimeString(), *event->GetEndTimeString(), event->Duration()/60); + header->DrawText(cPoint(20, offset + lineHeight), *datetime, theme.Color(clrFont), clrTransparent, tvguideConfig.FontDetailView); + header->DrawText(cPoint(20, offset + 2 * lineHeight), event->ShortText(), theme.Color(clrFont), clrTransparent, tvguideConfig.FontDetailView); +} + +void cDetailView::drawContent() { + content->Fill(theme.Color(clrBorder)); + content->DrawRectangle(cRect(2, 0, content->ViewPort().Width() - 2, content->DrawPort().Height()), theme.Color(clrBackground)); + + int textHeight = tvguideConfig.FontDetailView->Height(); + int textLines = description.Lines(); + + for (int i=0; i<textLines; i++) { + content->DrawText(cPoint(20, 20 + i*textHeight), description.GetLine(i), theme.Color(clrFont), clrTransparent, tvguideConfig.FontDetailView); + } +} + +void cDetailView::drawScrollbar() { + scrollBar->Fill(theme.Color(clrBorder)); + double scrollBarOffset = 0.0; + if (contentScrollable) { + heightScrollbar = ( (double)scrollBar->ViewPort().Height() ) / (double)heightContent * ( (double)scrollBar->ViewPort().Height() ); + scrollBarOffset = (-1.0)*(double)content->DrawPort().Point().Y() / (double)(content->DrawPort().Height() - (tvguideConfig.osdHeight-2*borderWidth-headerHeight)); + scrollBarOffset *= ( (double)scrollBar->ViewPort().Height()-7.0 - heightScrollbar); + scrollBarOffset++; + } else { + heightScrollbar = scrollBar->ViewPort().Height(); + } + scrollBar->DrawRectangle(cRect(3,0,scrollBar->ViewPort().Width()-6, scrollBar->ViewPort().Height()), theme.Color(clrBackground)); + if (imgScrollBar == NULL) { + imgScrollBar = createScrollbar(scrollBar->ViewPort().Width()-10, heightScrollbar, theme.Color(clrHighlight), theme.Color(clrHighlightBlending)); + } + scrollBar->DrawImage(cPoint(5, 2 + scrollBarOffset), *imgScrollBar); +} + +void cDetailView::scrollUp() { + if (contentScrollable) { + int newDrawportHeight = content->DrawPort().Point().Y() + tvguideConfig.FontDetailView->Height(); + content->SetDrawPortPoint(cPoint(0, min(newDrawportHeight,0))); + drawScrollbar(); + } +} + +void cDetailView::scrollDown() { + if (contentScrollable) { + int newDrawportHeight = content->DrawPort().Point().Y() - tvguideConfig.FontDetailView->Height(); + int maxDrawportHeight = (content->DrawPort().Height() - (tvguideConfig.osdHeight-2*borderWidth-headerHeight)); + content->SetDrawPortPoint(cPoint(0, max(newDrawportHeight,(-1)*maxDrawportHeight))); + drawScrollbar(); + } +} + +cImage *cDetailView::createScrollbar(int width, int height, tColor clrBgr, tColor clrBlend) { + cImage *image = new cImage(cSize(width, height)); + image->Fill(clrBgr); + if (tvguideConfig.useBlending) { + int numSteps = 64; + int alphaStep = 0x03; + if (height < 30) + return image; + else if (height < 100) { + numSteps = 32; + alphaStep = 0x06; + } + int stepY = 0.5*height / numSteps; + if (stepY == 0) + stepY = 1; + int alpha = 0x40; + tColor clr; + for (int i = 0; i<numSteps; i++) { + clr = AlphaBlend(clrBgr, clrBlend, alpha); + for (int y = i*stepY; y < (i+1)*stepY; y++) { + for (int x=0; x<width; x++) { + image->SetPixel(cPoint(x,y), clr); + } + } + alpha += alphaStep; + } + } + return image; +} + +void cDetailView::Action(void) { + drawHeader(); + drawContent(); + drawScrollbar(); + uint64_t Start = cTimeMs::Now(); + while (true) { + uint64_t Now = cTimeMs::Now(); + cPixmap::Lock(); + double t = min(double(Now - Start) / FadeTime, 1.0); + int Alpha = t * ALPHA_OPAQUE; + header->SetAlpha(Alpha); + content->SetAlpha(Alpha); + scrollBar->SetAlpha(Alpha); + footer->SetAlpha(Alpha); + osdManager.flush(); + cPixmap::Unlock(); + int Delta = cTimeMs::Now() - Now; + if (Delta < FrameTime) + cCondWait::SleepMs(FrameTime - Delta); + if ((Now - Start) > FadeTime) + break; + } +}
\ No newline at end of file diff --git a/detailview.h b/detailview.h new file mode 100644 index 0000000..c938eb2 --- /dev/null +++ b/detailview.h @@ -0,0 +1,39 @@ +#ifndef __TVGUIDE_DETAILVIEW_H +#define __TVGUIDE_DETAILVIEW_H + +// --- cDetailView ------------------------------------------------------------- + +class cEpgGrid; + +class cDetailView : public cThread { +private: + cEpgGrid *grid; + cStyledPixmap *header; + cPixmap *content; + cPixmap *scrollBar; + cPixmap *footer; + const cEvent *event; + cImage *imgScrollBar; + int FrameTime; + int FadeTime; + cTextWrapper description; + int borderWidth; + int headerHeight; + bool setContentDrawportHeight(); + int heightContent; + int heightScrollbar; + bool contentScrollable; + virtual void Action(void); + void drawHeader(); + void drawContent(); + void drawScrollbar(); + cImage *createScrollbar(int width, int height, tColor clrBgr, tColor clrBlend); +public: + cDetailView(cEpgGrid *grid); + virtual ~cDetailView(void); + void createPixmaps(); + void scrollUp(); + void scrollDown(); +}; + +#endif //__TVGUIDE_DETAILVIEW_H
\ No newline at end of file diff --git a/epggrid.c b/epggrid.c new file mode 100644 index 0000000..8c8109d --- /dev/null +++ b/epggrid.c @@ -0,0 +1,146 @@ +#include "channelcolumn.h"
+#include "epggrid.h"
+
+cEpgGrid::cEpgGrid(cChannelColumn *c, const cEvent *event) {
+ this->event = event;
+ this->column = c;
+ text = new cTextWrapper();
+ extText = new cTextWrapper();
+ dirty = true;
+ active = false;
+ viewportHeight = 0;
+ borderWidth = 10;
+ hasTimer = false;
+ if (column->hasTimer)
+ hasTimer = event->HasTimer();
+}
+
+cEpgGrid::~cEpgGrid(void) {
+ delete text;
+ delete extText;
+}
+
+void cEpgGrid::SetViewportHeight() {
+ int viewportHeightOld = viewportHeight;
+ if ( column->myTime->GetStart() > event->StartTime() ) {
+ viewportHeight = (min(event->EndTime(), column->myTime->GetStop()) - column->myTime->GetStart()) /60;
+ } else if ( column->myTime->GetStop() < event->EndTime() ) {
+ viewportHeight = (column->myTime->GetStop() - event->StartTime()) /60;
+ } else {
+ viewportHeight = event->Duration() / 60;
+ }
+ if (viewportHeight != viewportHeightOld)
+ dirty = true;
+}
+
+void cEpgGrid::PositionPixmap() {
+ int x0 = column->getX();
+ int y0 = tvguideConfig.headerHeight;
+ if ( column->myTime->GetStart() < event->StartTime() ) {
+ y0 += (event->StartTime() - column->myTime->GetStart())/60*tvguideConfig.minuteHeight;
+ }
+
+ if (!pixmap) {
+ caller = cString::sprintf("epggrid %s %s", column->channel->Name(), event->Title());
+ pixmap = osdManager.requestPixmap(-1, cRect(x0, y0, tvguideConfig.colWidth, viewportHeight * tvguideConfig.minuteHeight),
+ cRect(0, 0, tvguideConfig.colWidth, event->Duration()/60*tvguideConfig.minuteHeight), *caller);
+ } else {
+ pixmap->SetViewPort(cRect(x0, y0, tvguideConfig.colWidth, viewportHeight * tvguideConfig.minuteHeight));
+ }
+}
+
+void cEpgGrid::setBackground() {
+ if (active) {
+ color = theme.Color(clrHighlight);
+ colorBlending = theme.Color(clrHighlightBlending);
+ } else {
+ if (isColor1) {
+ color = theme.Color(clrGrid1);
+ colorBlending = theme.Color(clrGrid1Blending);
+ } else {
+ color = theme.Color(clrGrid2);
+ colorBlending = theme.Color(clrGrid2Blending);
+ }
+ }
+}
+
+void cEpgGrid::Draw() {
+ if (!pixmap) {
+ return;
+ }
+ if (dirty) {
+ setBackground();
+ drawBackground();
+ drawText();
+ if (hasTimer)
+ DrawRecIcon();
+ drawBorder();
+ pixmap->SetLayer(1);
+ dirty = false;
+ }
+}
+
+void cEpgGrid::DrawRecIcon() {
+ cString recIconText("REC");
+ int width = tvguideConfig.FontGrid->Width(*recIconText)+2*borderWidth;
+ int height = tvguideConfig.FontGrid->Height()+10;
+ pixmap->DrawRectangle( cRect(pixmap->ViewPort().Width() - width - borderWidth, pixmap->ViewPort().Height() - height - borderWidth, width, height), theme.Color(clrButtonRed));
+ pixmap->DrawText(cPoint(pixmap->ViewPort().Width() - width, pixmap->ViewPort().Height() - height - borderWidth/2), *recIconText, theme.Color(clrFont), clrTransparent, tvguideConfig.FontGrid);
+}
+
+void cEpgGrid::setText() {
+ cString strText;
+ strText = cString::sprintf("%s - %s:\n%s", *(event->GetTimeString()), *(event->GetEndTimeString()), event->Title());
+ text->Set(*(strText), tvguideConfig.FontGrid, tvguideConfig.colWidth-2*borderWidth);
+ extText->Set(event->ShortText(), tvguideConfig.FontGridSmall, tvguideConfig.colWidth-2*borderWidth);
+}
+
+void cEpgGrid::drawText() {
+ int gridHeight = pixmap->ViewPort().Height();
+ if (gridHeight/tvguideConfig.minuteHeight < 6)
+ return;
+ int textHeight = tvguideConfig.FontGrid->Height();
+ int textLines = text->Lines();
+ for (int i=0; i<textLines; i++) {
+ pixmap->DrawText(cPoint(borderWidth, borderWidth + i*textHeight), text->GetLine(i), theme.Color(clrFont), clrTransparent, tvguideConfig.FontGrid);
+ }
+ int extTextLines = extText->Lines();
+ int offset = (textLines+1)*textHeight - 0.5*textHeight;
+ textHeight = tvguideConfig.FontGridSmall->Height();
+ if ((pixmap->ViewPort().Height()-textHeight-10) > offset) {
+ for (int i=0; i<extTextLines; i++) {
+ pixmap->DrawText(cPoint(borderWidth, borderWidth + offset + i*textHeight), extText->GetLine(i), theme.Color(clrFont), clrTransparent, tvguideConfig.FontGridSmall);
+ }
+ }
+}
+
+int cEpgGrid::calcOverlap(cEpgGrid *neighbor) {
+ int overlap = 0;
+ if (intersects(neighbor)) {
+ if ((event->StartTime() <= neighbor->StartTime()) && (event->EndTime() <= neighbor->EndTime())) {
+ overlap = event->EndTime() - neighbor->StartTime();
+ } else if ((event->StartTime() >= neighbor->StartTime()) && (event->EndTime() >= neighbor->EndTime())) {
+ overlap = neighbor->EndTime() - event->StartTime();
+ } else if ((event->StartTime() >= neighbor->StartTime()) && (event->EndTime() <= neighbor->EndTime())) {
+ overlap = event->Duration();
+ } else if ((event->StartTime() <= neighbor->StartTime()) && (event->EndTime() >= neighbor->EndTime())) {
+ overlap = neighbor->EndTime() - neighbor->StartTime();
+ }
+ }
+ return overlap;
+}
+
+bool cEpgGrid::intersects(cEpgGrid *neighbor) {
+ return ! ( (neighbor->EndTime() <= event->StartTime()) || (neighbor->StartTime() >= event->EndTime()) );
+}
+
+bool cEpgGrid::isActiveInitial(time_t t) {
+ if ((event->StartTime() < t) && (event->EndTime() > t))
+ return true;
+ else
+ return false;
+}
+
+void cEpgGrid::debug() {
+ esyslog("tvguide Grid: %s, %s, viewportHeight: %d, Duration: %d", *(event->GetTimeString()), event->Title(), viewportHeight, event->Duration()/60);
+}
\ No newline at end of file diff --git a/epggrid.h b/epggrid.h new file mode 100644 index 0000000..00160dc --- /dev/null +++ b/epggrid.h @@ -0,0 +1,44 @@ +#ifndef __TVGUIDE_EPGGRID_H
+#define __TVGUIDE_EPGGRID_H
+
+// --- cEpgGrid -------------------------------------------------------------
+
+class cEpgGrid : public cListObject, public cStyledPixmap {
+private:
+ const cEvent *event;
+ cTextWrapper *text;
+ cTextWrapper *extText;
+ int viewportHeight;
+ int borderWidth;
+ void drawText();
+ void setBackground();
+ bool isColor1;
+ bool active;
+ bool dirty;
+ bool intersects(cEpgGrid *neighbor);
+ bool hasTimer;
+ void DrawRecIcon();
+public:
+ cEpgGrid(cChannelColumn *c, const cEvent *event);
+ virtual ~cEpgGrid(void);
+ cChannelColumn *column;
+ void SetViewportHeight();
+ void PositionPixmap();
+ void setText();
+ void Draw();
+ void SetDirty() {dirty = true;};
+ void SetActive() {dirty = true; active = true;};
+ void SetInActive() {dirty = true; active = false;};
+ void SetColor(bool color) {isColor1 = color;};
+ bool IsColor1() {return isColor1;};
+ int GetViewportHeight() {return viewportHeight;};
+ const cEvent *GetEvent() {return event;};
+ bool isActiveInitial(time_t t);
+ time_t StartTime() { return event->StartTime(); };
+ time_t EndTime() { return event->EndTime(); };
+ int calcOverlap(cEpgGrid *neighbor);
+ void setTimer() {hasTimer = true;};
+ void debug();
+};
+
+#endif //__TVGUIDE_EPGGRID_H
\ No newline at end of file diff --git a/footer.c b/footer.c new file mode 100644 index 0000000..19ee958 --- /dev/null +++ b/footer.c @@ -0,0 +1,59 @@ +#include "footer.h"
+
+cFooter::cFooter() {
+ int buttonHeight= tvguideConfig.footerHeight - 20;
+ textY = (buttonHeight - tvguideConfig.FontButton->Height())/2;
+ int distanceX = 20;
+ buttonWidth = (tvguideConfig.osdWidth - tvguideConfig.timeColWidth-5*distanceX)/4;
+ int startX = tvguideConfig.timeColWidth + distanceX;
+ int Y = tvguideConfig.osdHeight - tvguideConfig.footerHeight + (tvguideConfig.footerHeight - buttonHeight)/2;
+
+ buttonRed = new cStyledPixmap(osdManager.requestPixmap(3, cRect(startX, Y, buttonWidth, buttonHeight), cRect::Null, "btnRed"), "btnRed");
+ buttonGreen = new cStyledPixmap(osdManager.requestPixmap(3, cRect(startX + buttonWidth + distanceX, Y, buttonWidth, buttonHeight), cRect::Null, "btnGreen"), "btnGreen");
+ buttonYellow = new cStyledPixmap(osdManager.requestPixmap(3, cRect(startX + 2*(buttonWidth + distanceX), Y, buttonWidth, buttonHeight), cRect::Null, "btnYellow"), "btnYellow");
+ buttonBlue = new cStyledPixmap(osdManager.requestPixmap(3, cRect(startX + 3*(buttonWidth + distanceX), Y, buttonWidth, buttonHeight), cRect::Null, "btnBlue"), "btnBlue");
+}
+
+cFooter::~cFooter(void) {
+ delete buttonRed;
+ delete buttonGreen;
+ delete buttonYellow;
+ delete buttonBlue;
+}
+
+void cFooter::drawRedButton() {
+ buttonRed->setColor(theme.Color(clrButtonRed), theme.Color(clrButtonRedBlending));
+ buttonRed->drawBackground();
+ buttonRed->drawBorder();
+ cString text(tr("Set Timer"));
+ int width = tvguideConfig.FontButton->Width(*(text));
+ buttonRed->DrawText(cPoint((buttonWidth-width)/2, textY), *(text), theme.Color(clrFontButtons), clrTransparent, tvguideConfig.FontButton);
+
+}
+
+void cFooter::drawGreenButton() {
+ buttonGreen->setColor(theme.Color(clrButtonGreen), theme.Color(clrButtonGreenBlending));
+ buttonGreen->drawBackground();
+ buttonGreen->drawBorder();
+ cString text = cString::sprintf("%d %s", tvguideConfig.jumpChannels, tr("Channels back"));
+ int width = tvguideConfig.FontButton->Width(*text);
+ buttonGreen->DrawText(cPoint((buttonWidth-width)/2, textY), *text, theme.Color(clrFontButtons), clrTransparent, tvguideConfig.FontButton);
+}
+
+void cFooter::drawYellowButton() {
+ buttonYellow->setColor(theme.Color(clrButtonYellow), theme.Color(clrButtonYellowBlending));
+ buttonYellow->drawBackground();
+ buttonYellow->drawBorder();
+ cString text = cString::sprintf("%d %s", tvguideConfig.jumpChannels, tr("Channels forward"));
+ int width = tvguideConfig.FontButton->Width(*text);
+ buttonYellow->DrawText(cPoint((buttonWidth-width)/2, textY), *text, theme.Color(clrFontButtons), clrTransparent, tvguideConfig.FontButton);
+}
+
+void cFooter::drawBlueButton() {
+ buttonBlue->setColor(theme.Color(clrButtonBlue), theme.Color(clrButtonBlueBlending));
+ buttonBlue->drawBackground();
+ buttonBlue->drawBorder();
+ cString text(tr("Switch to Channel"));
+ int width = tvguideConfig.FontButton->Width(*(text));
+ buttonBlue->DrawText(cPoint((buttonWidth-width)/2, textY), *(text), theme.Color(clrFontButtons), clrTransparent, tvguideConfig.FontButton);
+}
diff --git a/footer.h b/footer.h new file mode 100644 index 0000000..9cf6045 --- /dev/null +++ b/footer.h @@ -0,0 +1,23 @@ +#ifndef __TVGUIDE_FOOTER_H
+#define __TVGUIDE_FOOTER_H
+
+// --- cFooter -------------------------------------------------------------
+
+class cFooter {
+private:
+ cStyledPixmap *buttonRed;
+ cStyledPixmap *buttonGreen;
+ cStyledPixmap *buttonYellow;
+ cStyledPixmap *buttonBlue;
+ int textY;
+ int buttonWidth;
+public:
+ cFooter();
+ virtual ~cFooter(void);
+ void drawRedButton();
+ void drawGreenButton();
+ void drawYellowButton();
+ void drawBlueButton();
+};
+
+#endif //__TVGUIDE_FOOTER_H
\ No newline at end of file diff --git a/imageloader.c b/imageloader.c new file mode 100644 index 0000000..015f805 --- /dev/null +++ b/imageloader.c @@ -0,0 +1,78 @@ +#include "imageloader.h" +#include <math.h> + +using namespace Magick; + +cImageLoader::cImageLoader() { +} + +cImageLoader::~cImageLoader() { +} + +bool cImageLoader::LoadLogo(const char *logo) +{ + try + { + int width = tvguideConfig.logoWidth; + int height = tvguideConfig.logoHeight; + cString extension; + if (tvguideConfig.logoExtension == 0) { + extension = "png"; + } else if (tvguideConfig.logoExtension == 1) { + extension = "jpg"; + } + cString Filename = cString::sprintf("%s%s.%s", *tvguideConfig.logoPath, logo, *extension); + osdImage.read(*Filename); + + if (height != 0 || width != 0) { + osdImage.sample( Geometry(width, height)); + + } + return true; + } + catch (...) + { + return false; + } +} + +bool cImageLoader::LoadEPGImage(int eventID) +{ + try + { + int width = tvguideConfig.epgImageWidth; + int height = tvguideConfig.epgImageHeight; + cString Filename = cString::sprintf("%s%d.jpg", *tvguideConfig.epgImagePath, eventID); + osdImage.read(*Filename); + + if (height != 0 || width != 0) + osdImage.sample( Geometry(width, height)); + + return true; + } + catch (...) + { + return false; + } +} + + +cImage cImageLoader::GetImage() +{ + int w, h; + w = osdImage.columns(); + h = osdImage.rows(); + cImage image (cSize(w, h)); + const PixelPacket *pixels = osdImage.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; +} diff --git a/imageloader.h b/imageloader.h new file mode 100644 index 0000000..c122758 --- /dev/null +++ b/imageloader.h @@ -0,0 +1,23 @@ +#ifndef _TVGUIDE_IMAGELOADER_H +#define _TVGUIDE_IMAGELOADER_H + +#define X_DISPLAY_MISSING + +#include <vdr/osd.h> +#include <vdr/skins.h> +#include <Magick++.h> + +using namespace Magick; + +class cImageLoader { +public: + cImageLoader(); + ~cImageLoader(); + cImage GetImage(); + bool LoadLogo(const char *logo); + bool LoadEPGImage(int eventID); +private: + Image osdImage; +}; + +#endif //_TVGUIDE_IMAGELOADER_H diff --git a/messagebox.c b/messagebox.c new file mode 100644 index 0000000..3f727d4 --- /dev/null +++ b/messagebox.c @@ -0,0 +1,114 @@ +#include "messagebox.h"
+
+cMessageBoxThread::cMessageBoxThread(cPixmap *content, int displayTime) {
+ this->content = content;
+ FrameTime = 30; // ms
+ FadeTime = 200; // ms
+ this->displayTime = displayTime;
+}
+
+cMessageBoxThread::~cMessageBoxThread(void) {
+ Cancel(0);
+}
+
+void cMessageBoxThread::Action(void) {
+ uint64_t Start = cTimeMs::Now();
+ while (Running()) {
+ uint64_t Now = cTimeMs::Now();
+ cPixmap::Lock();
+ double t = min(double(Now - Start) / FadeTime, 1.0);
+ int Alpha = t * ALPHA_OPAQUE;
+ if (content) {
+ content->SetAlpha(Alpha);
+ osdManager.flush();
+ }
+ cPixmap::Unlock();
+ int Delta = cTimeMs::Now() - Now;
+ if (Delta < FrameTime)
+ cCondWait::SleepMs(FrameTime - Delta);
+ if ((Now - Start) > FadeTime)
+ break;
+ }
+ cCondWait::SleepMs(displayTime - 2*FadeTime);
+ Start = cTimeMs::Now();
+ while (Running()) {
+ uint64_t Now = cTimeMs::Now();
+ cPixmap::Lock();
+ double t = min(double(Now - Start) / FadeTime, 1.0);
+ int Alpha = (1-t) * ALPHA_OPAQUE;
+ if (content) {
+ content->SetAlpha(Alpha);
+ osdManager.flush();
+ }
+ cPixmap::Unlock();
+ int Delta = cTimeMs::Now() - Now;
+ if (Delta < FrameTime)
+ cCondWait::SleepMs(FrameTime - Delta);
+ if ((Now - Start) > FadeTime)
+ break;
+ }
+ osdManager.flush();
+}
+
+//--cMessageBox-------------------------------------------------------------
+cMutex cMessageBox::mutex;
+cMessageBoxThread *cMessageBox::msgboxThread = NULL;
+cPixmap *cMessageBox::content = NULL;
+
+bool cMessageBox::Start(int displayTime, cString msg) {
+ cMutexLock MutexLock(&mutex);
+ int width = (tvguideConfig.osdWidth - 600)/2;
+ if (!content) {
+ int height = 400;
+ content = osdManager.requestPixmap(5, cRect((tvguideConfig.osdWidth - width)/2,
+ (tvguideConfig.osdHeight- height)/2,
+ width, height),
+ cRect::Null, "msgbox");
+ }
+ if (msgboxThread) {
+ delete msgboxThread;
+ msgboxThread = NULL;
+ }
+ if (!msgboxThread) {
+ msgboxThread = new cMessageBoxThread(content, displayTime);
+ cTextWrapper message;
+ message.Set(msg, tvguideConfig.FontMessageBox, width - 40);
+ int textHeight = tvguideConfig.FontMessageBox->Height();
+ int textLines = message.Lines();
+ int height = textLines * (textHeight+20);
+ cPixmap::Lock();
+ content->SetViewPort(cRect((tvguideConfig.osdWidth - width)/2,(tvguideConfig.osdHeight- height)/2, width, height));
+ content->SetAlpha(0);
+ content->Fill(theme.Color(clrBorder));
+ content->DrawRectangle(cRect(2,2,width-4, height-4), theme.Color(clrBackground));
+ int textWidth = 0;
+ for (int i=0; i<textLines; i++) {
+ textWidth = tvguideConfig.FontMessageBox->Width(message.GetLine(i));
+ content->DrawText(cPoint((width - textWidth)/2, 20 + i*textHeight), message.GetLine(i), theme.Color(clrFont), clrTransparent, tvguideConfig.FontMessageBox);
+ }
+ cPixmap::Unlock();
+ msgboxThread->Start();
+ return true;
+ }
+ return false;
+}
+
+void cMessageBox::Stop(void) {
+ cMutexLock MutexLock(&mutex);
+ if (msgboxThread) {
+ delete msgboxThread;
+ msgboxThread = NULL;
+ }
+}
+
+void cMessageBox::Destroy(void) {
+ cMutexLock MutexLock(&mutex);
+ if (msgboxThread) {
+ delete msgboxThread;
+ msgboxThread = NULL;
+ }
+ if (content) {
+ osdManager.releasePixmap(content, "msgboxDestroy");
+ content = NULL;
+ }
+}
diff --git a/messagebox.h b/messagebox.h new file mode 100644 index 0000000..8b9ab23 --- /dev/null +++ b/messagebox.h @@ -0,0 +1,31 @@ +#ifndef __TVGUIDE_MESSAGEBOX_H
+#define __TVGUIDE_MESSAGEBOX_H
+
+class cMessageBoxThreadPool;
+
+// --- cMessageBox -------------------------------------------------------------
+
+class cMessageBoxThread : public cThread {
+private:
+ cPixmap *content;
+ int FadeTime;
+ int FrameTime;
+ int displayTime;
+ virtual void Action(void);
+public:
+ cMessageBoxThread(cPixmap *content, int displayTime);
+ virtual ~cMessageBoxThread(void);
+};
+
+class cMessageBox {
+private:
+ static cMutex mutex;
+ static cMessageBoxThread *msgboxThread;
+ static cPixmap *content;
+public:
+ static bool Start(int displayTime, cString msg);
+ static void Stop(void);
+ static void Destroy(void);
+};
+
+#endif //__TVGUIDE_MESSAGEBOX_H
\ No newline at end of file diff --git a/osdmanager.c b/osdmanager.c new file mode 100644 index 0000000..fb0ec6e --- /dev/null +++ b/osdmanager.c @@ -0,0 +1,52 @@ +#ifndef __TVGUIDE_OSDMANAGER_H
+#define __TVGUIDE_OSDMANAGER_H
+
+class cOsdManager {
+ private:
+ cOsd *osd;
+ int activePixmaps;
+ public:
+ cOsdManager(void);
+ bool setOsd();
+ void setBackground();
+ void flush() {osd->Flush();};
+ cPixmap *requestPixmap(int Layer, const cRect &ViewPort, const cRect &DrawPort = cRect::Null, const char *caller = "anonymous");
+ void releasePixmap(cPixmap *pixmap, const char *caller = "anonymous");
+ void deleteOsd() {delete osd;};
+ int Width() { return osd->Width(); };
+ int Height() { return osd->Height(); };
+};
+
+#endif //__TVGUIDE_OSDMANAGER_H
+
+cOsdManager::cOsdManager(void) {
+ activePixmaps = 0;
+}
+
+bool cOsdManager::setOsd() {
+ osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop());
+ if (osd) {
+ tArea Area = { 0, 0, cOsd::OsdWidth(), cOsd::OsdHeight(), 32 };
+ if (osd->SetAreas(&Area, 1) == oeOk) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void cOsdManager::setBackground() {
+ osd->DrawRectangle(0, 0, cOsd::OsdWidth(), cOsd::OsdHeight(), theme.Color(clrBackgroundOSD));
+}
+cPixmap *cOsdManager::requestPixmap(int Layer, const cRect &ViewPort, const cRect &DrawPort, const char *caller) {
+ if (activePixmaps >= 64)
+ return NULL;
+ activePixmaps++;
+ //esyslog("tvguide: Pixmap angefordert von %s, verwendet: %d", caller, activePixmaps);
+ return osd->CreatePixmap(Layer, ViewPort, DrawPort);
+ }
+
+void cOsdManager::releasePixmap(cPixmap *pixmap, const char *caller) {
+ activePixmaps--;
+ //esyslog("tvguide: Pixmap geloescht von %s, verwendet: %d", caller, activePixmaps);
+ osd->DestroyPixmap(pixmap);
+}
\ No newline at end of file diff --git a/po/de_DE.po b/po/de_DE.po new file mode 100755 index 0000000..bdf0cd8 --- /dev/null +++ b/po/de_DE.po @@ -0,0 +1,139 @@ +# VDR plugin language source file. +msgid "" +msgstr "" +"Project-Id-Version: vdr-tvguide 0.0.1\n" +"Report-Msgid-Bugs-To: <see README>\n" +"POT-Creation-Date: 2012-12-27 15:27+0100\n" +"PO-Revision-Date: 2012-08-25 17:49+0200\n" +"Last-Translator: Horst\n" +"Language-Team: \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "Set Timer" +msgstr "Aufnehmen" + +msgid "Channels back" +msgstr "Kanäle zurück" + +msgid "Channels forward" +msgstr "Kanäle vor" + +msgid "Switch to Channel" +msgstr "Umschalten" + +msgid "General Settings" +msgstr "Allgemeine Einstellungen" + +msgid "Screen Presentation" +msgstr "Anzeigeoptionen" + +msgid "Fonts and Fontsizes" +msgstr "Schriften und Schriftgrößen" + +msgid "Number of Channels / Columns" +msgstr "Anzahl der Kanäle bzw. Spalten" + +msgid "Channels to Jump (Keys Green / Yellow)" +msgstr "Kanalsprung (Tasten Grün / Gelb)" + +msgid "Time to display vertically in minutes" +msgstr "Vertikal angezeigte Zeit (in Minuten)" + +msgid "Big Step (Keys 1 / 3) in hours" +msgstr "Großer Sprung (Tasten 1 / 3) in Stunden" + +msgid "Huge Step (Keys 4 / 6) in hours" +msgstr "Sehr großer Sprung (Tasten 4 / 6) in Stunden" + +msgid "Time Format (12h/24h)" +msgstr "Zeitformat (12h/24h)" + +msgid "Theme" +msgstr "Theme" + +msgid "Use color gradients" +msgstr "Farbverläufe verwenden" + +msgid "Rounded Corners" +msgstr "Abgerundete Ecken" + +msgid "Width of Timeline" +msgstr "Breite der Zeitleiste" + +msgid "Height of Header" +msgstr "Höhe des Headers" + +msgid "Height of Footer" +msgstr "Höhe des Footers" + +msgid "Show Channel Logos" +msgstr "Kanallogos anzeigen" + +msgid "Logo Path used" +msgstr "Benutzer Pfad für Kanallogos" + +msgid "Logo Extension" +msgstr "Logo Extension" + +msgid "Logo width" +msgstr "Breite der Logos" + +msgid "Logo height" +msgstr "Höhe der Logos" + +msgid "Show EPG Images" +msgstr "EPG Bilder anzeigen" + +msgid "EPG Images Path used" +msgstr "benutzer EPG Bilder Pfad" + +msgid "EPG Image width" +msgstr "Breite der EPG Bilder" + +msgid "EPG Image height" +msgstr "Höhe der EPG Bilder" + +msgid "Font" +msgstr "Schriftart" + +msgid "Channel Header Font Size" +msgstr "Kanal Header Schriftgröße" + +msgid "Grid Font Size" +msgstr "Grid Schriftgröße" + +msgid "Grid Font Small Size" +msgstr "Grid kleine Schriftgröße" + +msgid "Timeline Weekday Font Size" +msgstr "Zeitleiste Wochentag Schriftgröße" + +msgid "Timeline Date Font Size" +msgstr "Zeitleiste Datum Schriftgröße" + +msgid "Timeline Time Font Size" +msgstr "Zeitleiste Zeit Schriftgröße" + +msgid "Button Font Size" +msgstr "Button Schriftgröße" + +msgid "Detail EPG View Font Size" +msgstr "Detailierte EPG Ansicht Schriftgröße" + +msgid "Detail EPG View Header Font Size" +msgstr "Detailierte EPG Ansicht Header Schriftgröße" + +msgid "Message Font Size" +msgstr "Nachrichten Schriftgröße" + +msgid "Message Large Font Size" +msgstr "Nachrichten große Schriftgröße" + +msgid "Timer not set! There is already a timer for this item." +msgstr "Timer wurde nicht gesetzt! Es existiert bereits ein Timer für diese Sendung" + +msgid "Timer set" +msgstr "Timer gesetzt" @@ -0,0 +1,209 @@ +#include "setup.h" + +cTvguideSetup::cTvguideSetup() { + tmpTvguideConfig = tvguideConfig; + Setup(); +} + +cTvguideSetup::~cTvguideSetup() { +} + + +void cTvguideSetup::Setup(void) { + int currentItem = Current(); + Clear(); + + Add(new cOsdItem(tr("General Settings"))); + Add(new cOsdItem(tr("Screen Presentation"))); + Add(new cOsdItem(tr("Fonts and Fontsizes"))); + + SetCurrent(Get(currentItem)); + Display(); +} + +eOSState cTvguideSetup::ProcessKey(eKeys Key) { + bool hadSubMenu = HasSubMenu(); + eOSState state = cMenuSetupPage::ProcessKey(Key); + if (hadSubMenu && Key == kOk) + Store(); + + if (!hadSubMenu && (state == osUnknown || Key == kOk)) { + if ((Key == kOk && !hadSubMenu)) { + const char* ItemText = Get(Current())->Text(); + if (strcmp(ItemText, tr("General Settings")) == 0) + state = AddSubMenu(new cMenuSetupGeneral(&tmpTvguideConfig)); + if (strcmp(ItemText, tr("Screen Presentation")) == 0) + state = AddSubMenu(new cMenuSetupScreenLayout(&tmpTvguideConfig)); + if (strcmp(ItemText, tr("Fonts and Fontsizes")) == 0) + state = AddSubMenu(new cMenuSetupFont(&tmpTvguideConfig)); + } + } + return state; +} + +void cTvguideSetup::Store(void) { + + tvguideConfig = tmpTvguideConfig; + + SetupStore("themeIndex", tvguideConfig.themeIndex); + SetupStore("useBlending", tvguideConfig.useBlending); + SetupStore("roundedCorners", tvguideConfig.roundedCorners); + SetupStore("timeFormat", tvguideConfig.timeFormat); + SetupStore("channelCols", tvguideConfig.channelCols); + SetupStore("displayTime", tvguideConfig.displayTime); + SetupStore("bigStepHours", tvguideConfig.bigStepHours); + SetupStore("hugeStepHours", tvguideConfig.hugeStepHours); + SetupStore("jumpChannels", tvguideConfig.jumpChannels); + SetupStore("hideChannelLogos", tvguideConfig.hideChannelLogos); + SetupStore("logoExtension", tvguideConfig.logoExtension); + SetupStore("logoWidth", tvguideConfig.logoWidth); + SetupStore("logoHeight", tvguideConfig.logoHeight); + SetupStore("hideEpgImages", tvguideConfig.hideEpgImages); + SetupStore("epgImageWidth", tvguideConfig.epgImageWidth); + SetupStore("epgImageHeight", tvguideConfig.epgImageHeight); + SetupStore("epgImageHeight", tvguideConfig.epgImageHeight); + SetupStore("timeColWidth", tvguideConfig.timeColWidth); + SetupStore("headerHeight", tvguideConfig.headerHeight); + SetupStore("footerHeight", tvguideConfig.footerHeight); + SetupStore("fontIndex", tvguideConfig.fontIndex); + SetupStore("fontHeaderSize", tvguideConfig.fontHeaderSize); + SetupStore("fontGridSize", tvguideConfig.fontGridSize); + SetupStore("fontGridSmallSize", tvguideConfig.fontGridSmallSize); + SetupStore("fontTimeLineWeekdaySize", tvguideConfig.fontTimeLineWeekdaySize); + SetupStore("fontTimeLineDateSize", tvguideConfig.fontTimeLineDateSize); + SetupStore("fontTimeLineTimeSize", tvguideConfig.fontTimeLineTimeSize); + SetupStore("fontButtonSize", tvguideConfig.fontButtonSize); + SetupStore("fontDetailViewSize", tvguideConfig.fontDetailViewSize); + SetupStore("fontDetailHeaderSize", tvguideConfig.fontDetailHeaderSize); + SetupStore("fontMessageBoxSize", tvguideConfig.fontMessageBoxSize); + SetupStore("fontMessageBoxLargeSize", tvguideConfig.fontMessageBoxLargeSize); +} + +cMenuSetupSubMenu::cMenuSetupSubMenu(const char* Title, cTvguideConfig* data) : cOsdMenu(Title, 30) { + tmpTvguideConfig = data; +} + +cOsdItem *cMenuSetupSubMenu::InfoItem(const char *label, const char *value) { + cOsdItem *item; + item = new cOsdItem(cString::sprintf("%s: %s", label, value)); + item->SetSelectable(false); + return item; +} + +eOSState cMenuSetupSubMenu::ProcessKey(eKeys Key) { + eOSState state = cOsdMenu::ProcessKey(Key); + if (state == osUnknown) { + switch (Key) { + case kOk: + return osBack; + default: + break; + } + } + return state; +} + +//------------------------------------------------------------------------------------------------------------------ + +cMenuSetupGeneral::cMenuSetupGeneral(cTvguideConfig* data) : cMenuSetupSubMenu(tr("General Settings"), data) { + timeFormatItems[0] = "12h"; + timeFormatItems[1] = "24h"; + + Set(); +} + +void cMenuSetupGeneral::Set(void) { + int currentItem = Current(); + Clear(); + + Add(new cMenuEditIntItem(tr("Number of Channels / Columns"), &tmpTvguideConfig->channelCols, 3, 8)); + Add(new cMenuEditIntItem(tr("Channels to Jump (Keys Green / Yellow)"), &tmpTvguideConfig->jumpChannels, 2, 30)); + Add(new cMenuEditIntItem(tr("Time to display vertically in minutes"), &tmpTvguideConfig->displayTime, 120, 320)); + Add(new cMenuEditIntItem(tr("Big Step (Keys 1 / 3) in hours"), &tmpTvguideConfig->bigStepHours, 1, 12)); + Add(new cMenuEditIntItem(tr("Huge Step (Keys 4 / 6) in hours"), &tmpTvguideConfig->hugeStepHours, 13, 48)); + Add(new cMenuEditStraItem(tr("Time Format (12h/24h)"), &tmpTvguideConfig->timeFormat, 2, timeFormatItems)); + + SetCurrent(Get(currentItem)); + Display(); +} + +//------------------------------------------------------------------------------------------------------------------ + +cMenuSetupScreenLayout::cMenuSetupScreenLayout(cTvguideConfig* data) : cMenuSetupSubMenu(tr("Screen Presentation"), data) { + themes.Load(*cString("tvguide")); + hideChannelLogosItems[0] = trVDR("yes"); + hideChannelLogosItems[1] = trVDR("no"); + logoExtensionItems[0] = "png"; + logoExtensionItems[1] = "jpg"; + Set(); +} + +void cMenuSetupScreenLayout::Set(void) { + int currentItem = Current(); + Clear(); + if (themes.NumThemes()) + Add(new cMenuEditStraItem(tr("Theme"), &tmpTvguideConfig->themeIndex, themes.NumThemes(), themes.Descriptions())); + Add(new cMenuEditBoolItem(tr("Use color gradients"), &tmpTvguideConfig->useBlending)); + Add(new cMenuEditBoolItem(tr("Rounded Corners"), &tmpTvguideConfig->roundedCorners)); + Add(new cMenuEditIntItem(tr("Width of Timeline"), &tmpTvguideConfig->timeColWidth, 50, 300)); + Add(new cMenuEditIntItem(tr("Height of Header"), &tmpTvguideConfig->headerHeight, 50, 300)); + Add(new cMenuEditIntItem(tr("Height of Footer"), &tmpTvguideConfig->footerHeight, 50, 300)); + + const char *indent = " "; + Add(new cMenuEditStraItem(tr("Show Channel Logos"), &tmpTvguideConfig->hideChannelLogos, 2, hideChannelLogosItems)); + if (!tmpTvguideConfig->hideChannelLogos) { + Add(InfoItem(tr("Logo Path used"), *tvguideConfig.logoPath)); + Add(new cMenuEditStraItem(*cString::sprintf("%s%s", indent, tr("Logo Extension")), &tmpTvguideConfig->logoExtension, 2, logoExtensionItems)); + Add(new cMenuEditIntItem(*cString::sprintf("%s%s", indent, tr("Logo width")), &tmpTvguideConfig->logoWidth, 0, 350)); + Add(new cMenuEditIntItem(*cString::sprintf("%s%s", indent, tr("Logo height")), &tmpTvguideConfig->logoHeight, 0, 250)); + } + + Add(new cMenuEditStraItem(tr("Show EPG Images"), &tmpTvguideConfig->hideEpgImages, 2, hideChannelLogosItems)); + if (!tmpTvguideConfig->hideEpgImages) { + Add(InfoItem(tr("EPG Images Path used"), *tvguideConfig.epgImagePath)); + Add(new cMenuEditIntItem(*cString::sprintf("%s%s", indent, tr("EPG Image width")), &tmpTvguideConfig->epgImageWidth, 0, 800)); + Add(new cMenuEditIntItem(*cString::sprintf("%s%s", indent, tr("EPG Image height")), &tmpTvguideConfig->epgImageHeight, 0, 800)); + } + + SetCurrent(Get(currentItem)); + Display(); +} + +eOSState cMenuSetupScreenLayout::ProcessKey(eKeys Key) { + eOSState state = cOsdMenu::ProcessKey(Key); + if (Key == kOk) { + state = osBack; + } else if (Key != kNone) { + Set(); + } + return state; +} + +//------------------------------------------------------------------------------------------------------------------ + +cMenuSetupFont::cMenuSetupFont(cTvguideConfig* data) : cMenuSetupSubMenu(tr("Fonts and Fontsizes"), data) { + cFont::GetAvailableFontNames(&fontNames); + fontNames.Insert(strdup(tvguideConfig.fontNameDefault)); + Set(); +} + +void cMenuSetupFont::Set(void) { + int currentItem = Current(); + Clear(); + + Add(new cMenuEditStraItem(tr("Font"), &tmpTvguideConfig->fontIndex, fontNames.Size(), &fontNames[0])); + Add(new cMenuEditIntItem(tr("Channel Header Font Size"), &tmpTvguideConfig->fontHeaderSize, 10, 70)); + Add(new cMenuEditIntItem(tr("Grid Font Size"), &tmpTvguideConfig->fontGridSize, 10, 70)); + Add(new cMenuEditIntItem(tr("Grid Font Small Size"), &tmpTvguideConfig->fontGridSmallSize, 10, 70)); + Add(new cMenuEditIntItem(tr("Timeline Weekday Font Size"), &tmpTvguideConfig->fontTimeLineWeekdaySize, 10, 70)); + Add(new cMenuEditIntItem(tr("Timeline Date Font Size"), &tmpTvguideConfig->fontTimeLineDateSize, 10, 70)); + Add(new cMenuEditIntItem(tr("Timeline Time Font Size"), &tmpTvguideConfig->fontTimeLineTimeSize, 10, 70)); + Add(new cMenuEditIntItem(tr("Button Font Size"), &tmpTvguideConfig->fontButtonSize, 10, 70)); + Add(new cMenuEditIntItem(tr("Detail EPG View Font Size"), &tmpTvguideConfig->fontDetailViewSize, 10, 70)); + Add(new cMenuEditIntItem(tr("Detail EPG View Header Font Size"), &tmpTvguideConfig->fontDetailHeaderSize, 10, 70)); + Add(new cMenuEditIntItem(tr("Message Font Size"), &tmpTvguideConfig->fontMessageBoxSize, 10, 70)); + Add(new cMenuEditIntItem(tr("Message Large Font Size"), &tmpTvguideConfig->fontMessageBoxLargeSize, 10, 70)); + + SetCurrent(Get(currentItem)); + Display(); +}
\ No newline at end of file @@ -0,0 +1,54 @@ +#ifndef __TVGUIDE_SETUP_H +#define __TVGUIDE_SETUP_H + +class cTvguideSetup : public cMenuSetupPage { + public: + cTvguideSetup(void); + virtual ~cTvguideSetup(); + private: + cTvguideConfig tmpTvguideConfig; + void Setup(void); + protected: + virtual eOSState ProcessKey(eKeys Key); + virtual void Store(void); + +}; + +class cMenuSetupSubMenu : public cOsdMenu { + protected: + cTvguideConfig *tmpTvguideConfig; + virtual eOSState ProcessKey(eKeys Key); + virtual void Set(void) = 0; + cOsdItem *InfoItem(const char *label, const char *value); + public: + cMenuSetupSubMenu(const char *Title, cTvguideConfig *data); +}; + +class cMenuSetupGeneral : public cMenuSetupSubMenu { + protected: + const char * timeFormatItems[2]; + void Set(void); + public: + cMenuSetupGeneral(cTvguideConfig *data); +}; + +class cMenuSetupScreenLayout : public cMenuSetupSubMenu { + protected: + virtual eOSState ProcessKey(eKeys Key); + cThemes themes; + const char * hideChannelLogosItems[2]; + const char * logoExtensionItems[2]; + void Set(void); + public: + cMenuSetupScreenLayout(cTvguideConfig *data); +}; + +class cMenuSetupFont : public cMenuSetupSubMenu { + protected: + cStringList fontNames; + void Set(void); + public: + cMenuSetupFont(cTvguideConfig *data); +}; + +#endif //__TVGUIDE_SETUP_H
\ No newline at end of file diff --git a/styledpixmap.c b/styledpixmap.c new file mode 100644 index 0000000..2569f53 --- /dev/null +++ b/styledpixmap.c @@ -0,0 +1,125 @@ +#include "styledpixmap.h"
+
+cStyledPixmap::cStyledPixmap(void) {
+ pixmap = NULL;
+ caller = NULL;
+}
+
+cStyledPixmap::cStyledPixmap(cPixmap *pixmap, cString caller) {
+ this->pixmap = pixmap;
+ this->caller = caller;
+}
+
+cStyledPixmap::~cStyledPixmap(void) {
+ if (pixmap)
+ osdManager.releasePixmap(pixmap, *caller);
+}
+
+void cStyledPixmap::setPixmap(cPixmap *pixmap) {
+ if (pixmap) {
+ this->pixmap = pixmap;
+ }
+}
+
+void cStyledPixmap::drawBackground() {
+ if (!tvguideConfig.useBlending) {
+ pixmap->Fill(color);
+ } else {
+ drawBlendedBackground();
+ }
+}
+
+void cStyledPixmap::drawBlendedBackground() {
+ int width = pixmap->ViewPort().Width();
+ int height = pixmap->ViewPort().Height();
+ pixmap->Fill(color);
+ int numSteps = 64;
+ int alphaStep = 0x04;
+ if (height < 30)
+ return;
+ else if (height < 100) {
+ numSteps = 32;
+ alphaStep = 0x08;
+ }
+ int stepY = 0.5*height / numSteps;
+ if (stepY == 0) stepY = 1;
+ int alpha = 0x00;
+ tColor clr;
+ for (int i = 0; i<numSteps; i++) {
+ clr = AlphaBlend(color, colorBlending, alpha);
+ pixmap->DrawRectangle(cRect(0,i*stepY,width,stepY), clr);
+ alpha += alphaStep;
+ }
+}
+
+void cStyledPixmap::drawBorder() {
+ int width = pixmap->ViewPort().Width();
+ int height = pixmap->ViewPort().Height();
+
+ drawDefaultBorder(width, height);
+ if (tvguideConfig.roundedCorners) {
+ int borderRadius = 12;
+ drawRoundedCorners(width, height, borderRadius);
+ }
+}
+
+void cStyledPixmap::drawDefaultBorder(int width, int height) {
+ pixmap->DrawRectangle(cRect(0,0,width,2), theme.Color(clrBackground)); //top
+ pixmap->DrawRectangle(cRect(0,0,2,height), theme.Color(clrBackground)); //left
+ pixmap->DrawRectangle(cRect(0,height-2,width,2), theme.Color(clrBackground)); //bottom
+ pixmap->DrawRectangle(cRect(width-2,0,2,height), theme.Color(clrBackground)); //right
+
+ pixmap->DrawRectangle(cRect(2,2,width-4,1), theme.Color(clrBorder)); //top
+ pixmap->DrawRectangle(cRect(2,2,1,height-4), theme.Color(clrBorder)); //left
+ pixmap->DrawRectangle(cRect(2,height-3,width-4,1), theme.Color(clrBorder)); //bottom
+ pixmap->DrawRectangle(cRect(width-3,2,1,height-4), theme.Color(clrBorder)); //right
+}
+
+void cStyledPixmap::drawBoldBorder() {
+ int width = pixmap->ViewPort().Width();
+ int height = pixmap->ViewPort().Height();
+ pixmap->DrawRectangle(cRect(0,0,width,2), theme.Color(clrBorder)); //top
+ pixmap->DrawRectangle(cRect(0,0,2,height), theme.Color(clrBorder)); //left
+ pixmap->DrawRectangle(cRect(0,height-2,width,2), theme.Color(clrBorder)); //bottom
+ pixmap->DrawRectangle(cRect(width-2,0,2,height), theme.Color(clrBorder)); //right
+}
+
+void cStyledPixmap::drawRoundedCorners(int width, int height, int radius) {
+ pixmap->DrawEllipse(cRect(2,2,radius,radius), theme.Color(clrBorder), -2);
+ pixmap->DrawEllipse(cRect(1,1,radius,radius), theme.Color(clrBackground), -2);
+
+ pixmap->DrawEllipse(cRect(width-radius - 2,2,radius,radius), theme.Color(clrBorder), -1);
+ pixmap->DrawEllipse(cRect(width-radius - 1,1,radius,radius), theme.Color(clrBackground), -1);
+
+ if( height > 2*radius) {
+ pixmap->DrawEllipse(cRect(2,height-radius - 2,radius,radius), theme.Color(clrBorder), -3);
+ pixmap->DrawEllipse(cRect(1,height-radius - 1,radius,radius), theme.Color(clrBackground), -3);
+
+ pixmap->DrawEllipse(cRect(width-radius - 2,height-radius - 2,radius,radius), theme.Color(clrBorder), -4);
+ pixmap->DrawEllipse(cRect(width-radius - 1,height-radius - 1,radius,radius), theme.Color(clrBackground), -4);
+ }
+}
+
+void cStyledPixmap::drawVerticalLine(int x, int yStart, int yStop, tColor col) {
+ for (int y = yStart; y <= yStop; y++) {
+ pixmap->DrawPixel(cPoint(x,y), col);
+ }
+}
+
+void cStyledPixmap::drawHorizontalLine(int y, int xStart, int xStop, tColor col) {
+ for (int x = xStart; x <= xStop; x++) {
+ pixmap->DrawPixel(cPoint(x,y), col);
+ }
+}
+
+void cStyledPixmap::DrawText(const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font) {
+ pixmap->DrawText(Point, s, ColorFg, ColorBg, Font);
+}
+
+void cStyledPixmap::DrawImage(const cPoint &Point, const cImage &Image) {
+ pixmap->DrawImage(Point, Image);
+}
+
+void cStyledPixmap::DrawRectangle(const cRect &Rect, tColor Color) {
+ pixmap->DrawRectangle(Rect,Color);
+}
diff --git a/styledpixmap.h b/styledpixmap.h new file mode 100644 index 0000000..a751032 --- /dev/null +++ b/styledpixmap.h @@ -0,0 +1,35 @@ +#ifndef __TVGUIDE_STYLEDPIXMAP_H
+#define __TVGUIDE_STYLEDPIXMAP_H
+
+// --- cStyledPixmap -------------------------------------------------------------
+
+class cStyledPixmap {
+private:
+ void drawVerticalLine(int x, int yStart, int yStop, tColor col);
+ void drawHorizontalLine(int y, int xStart, int xStop, tColor col);
+protected:
+ cPixmap *pixmap;
+ cString caller;
+ tColor color;
+ tColor colorBlending;
+ void setPixmap(cPixmap *pixmap);
+public:
+ cStyledPixmap(void);
+ cStyledPixmap(cPixmap *pixmap, cString caller);
+ virtual ~cStyledPixmap(void);
+ void drawBackground();
+ void drawBlendedBackground();
+ void drawBorder();
+ void drawBoldBorder();
+ void drawDefaultBorder(int width, int height);
+ void drawRoundedCorners(int width, int height, int radius);
+ void setColor(tColor color, tColor colorBlending) {this->color = color; this->colorBlending = colorBlending;};
+ void SetAlpha(int alpha) {pixmap->SetAlpha(alpha);};
+ void DrawText(const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font);
+ void DrawImage(const cPoint &Point, const cImage &Image);
+ void DrawRectangle(const cRect &Rect, tColor Color);
+ int Width() {return pixmap->ViewPort().Width();};
+ int Height() {return pixmap->ViewPort().Height();};
+};
+
+#endif //__TVGUIDE_STYLEDPIXMAP_H
\ No newline at end of file diff --git a/themes/tvguide-darkblue.theme b/themes/tvguide-darkblue.theme new file mode 100644 index 0000000..4040458 --- /dev/null +++ b/themes/tvguide-darkblue.theme @@ -0,0 +1,28 @@ +Description = DarkBlue + +clrBackground = FF000000 +clrBackgroundOSD = FF000000 +clrGrid1 = FF0E53A7 +clrGrid1Blending = FF000000 +clrGrid2 = FF071871 +clrGrid2Blending = FF000000 +clrHighlight = FF7A6D6D +clrHighlightBlending = FF1C1919 +clrFont = FFFFFFFF +clrFontHeader = FF000000 +clrFontButtons = FFFFFFFF +clrHeader = FF8B9194 +clrHeaderBlending = FF000000 +clrBorder = FFFFFFFF +clrTimeline1 = FFFFFFFF +clrTimeline1Blending = FF828282 +clrTimeline2 = FF000000 +clrTimeline2Blending = FF3F3F3F +clrButtonRed = FFD42627 +clrButtonRedBlending = FF000000 +clrButtonGreen = FF004F00 +clrButtonGreenBlending = FF000000 +clrButtonYellow = FFFFA300 +clrButtonYellowBlending = FF000000 +clrButtonBlue = FF0000FE +clrButtonBlueBlending = FF000000 diff --git a/themes/tvguide-default.theme b/themes/tvguide-default.theme new file mode 100644 index 0000000..e1e5794 --- /dev/null +++ b/themes/tvguide-default.theme @@ -0,0 +1,27 @@ +Description = Default +clrBackground = FF000000 +clrBackgroundOSD = FF000000 +clrGrid1 = FF404749 +clrGrid1Blending = FF000000 +clrGrid2 = FF20293F +clrGrid2Blending = FF000000 +clrHighlight = FFFF4D00 +clrHighlightBlending = FF000000 +clrFont = FFFFFFFF +clrFontHeader = FFFFFFFF +clrFontButtons = FFFFFFFF +clrHeader = FF000000 +clrHeaderBlending = FFE0E0E0 +clrBorder = FFFFFFFF +clrTimeline1 = FFFFFFFF +clrTimeline1Blending = FF828282 +clrTimeline2 = FF000000 +clrTimeline2Blending = FF3F3F3F +clrButtonRed = FFD42627 +clrButtonRedBlending = FFE0E0E0 +clrButtonGreen = FF004F00 +clrButtonGreenBlending = FFE0E0E0 +clrButtonYellow = FFFFA300 +clrButtonYellowBlending = FFE0E0E0 +clrButtonBlue = FF0000FE +clrButtonBlueBlending = FFE0E0E0 diff --git a/timeline.c b/timeline.c new file mode 100644 index 0000000..e2275fd --- /dev/null +++ b/timeline.c @@ -0,0 +1,115 @@ +#include "timeline.h"
+
+cTimeLine::cTimeLine(cMyTime *myTime) {
+ this->myTime = myTime;
+ dateViewer = new cStyledPixmap(osdManager.requestPixmap(3, cRect(0, 0, tvguideConfig.timeColWidth, tvguideConfig.headerHeight), cRect::Null, "dateViewer"), "dateViewer");
+ timeline = osdManager.requestPixmap(2, cRect(0, tvguideConfig.headerHeight, tvguideConfig.timeColWidth, tvguideConfig.osdHeight - tvguideConfig.headerHeight - tvguideConfig.footerHeight),
+ cRect(0,0, tvguideConfig.timeColWidth, 1440*tvguideConfig.minuteHeight), "timeline");
+ clock = new cStyledPixmap(osdManager.requestPixmap(3, cRect(0, tvguideConfig.osdHeight-tvguideConfig.footerHeight, tvguideConfig.timeColWidth, tvguideConfig.footerHeight-9), cRect::Null, "timeViewer"), "timeViewer");
+}
+
+cTimeLine::~cTimeLine(void) {
+ delete dateViewer;
+ osdManager.releasePixmap(timeline);
+ delete clock;
+}
+
+void cTimeLine::drawDateViewer() {
+ cString weekDay = myTime->GetWeekday();
+ cString date = myTime->GetDate();
+
+ int textHeight = tvguideConfig.FontTimeLineWeekday->Height();
+ int weekdayWidth = tvguideConfig.FontTimeLineWeekday->Width(*weekDay);
+ int dateWidth = tvguideConfig.FontTimeLineDate->Width(*date);
+
+ dateViewer->setColor(theme.Color(clrHeader), theme.Color(clrHeaderBlending));
+ dateViewer->drawBackground();
+ dateViewer->drawBorder();
+ dateViewer->DrawText(cPoint((tvguideConfig.timeColWidth-weekdayWidth)/2, (tvguideConfig.headerHeight-2*textHeight)/2), *weekDay, theme.Color(clrFontHeader), clrTransparent, tvguideConfig.FontTimeLineWeekday);
+ dateViewer->DrawText(cPoint((tvguideConfig.timeColWidth-dateWidth)/2, (tvguideConfig.headerHeight-2*textHeight)/2 + textHeight + 5), *date, theme.Color(clrFontHeader), clrTransparent, tvguideConfig.FontTimeLineDate);
+}
+
+void cTimeLine::drawTimeline() {
+ timeline->SetTile(true);
+ timeline->Fill(theme.Color(clrBackground));
+ tColor colorFont;
+
+ const cImage *img1 = createBackgroundImage(tvguideConfig.timeColWidth-4, tvguideConfig.minuteHeight*30, theme.Color(clrTimeline1), theme.Color(clrTimeline1Blending));
+ const cImage *img2 = createBackgroundImage(tvguideConfig.timeColWidth-4, tvguideConfig.minuteHeight*30, theme.Color(clrTimeline2), theme.Color(clrTimeline2Blending));
+ const cImage *img = NULL;
+
+ int textWidth, posY;
+ char timetext[10];
+
+ for (int i=0; i<48; i++) {
+ if (i%2==0) {
+ img = img1;
+ colorFont = theme.Color(clrTimeline2);
+ if (tvguideConfig.timeFormat == e12Hours) {
+ if (i == 0)
+ sprintf(timetext, "12:00 PM");
+ else if (i/2 < 13)
+ sprintf(timetext, "%d:00 AM", i/2);
+ else
+ sprintf(timetext, "%d:00 PM", i/2-12);
+ } else {
+ sprintf(timetext, "%d:00", i/2);
+ }
+ } else {
+ img = img2;
+ colorFont = theme.Color(clrTimeline1);
+ if (tvguideConfig.timeFormat == e12Hours) {
+ if (i == 1)
+ sprintf(timetext, "12:30 PM");
+ else if (i/2 < 13)
+ sprintf(timetext, "%d:30 AM", i/2);
+ else
+ sprintf(timetext, "%d:30 PM", i/2-12);
+ } else {
+ sprintf(timetext, "%d:30", i/2);
+ }
+ }
+ posY = i*tvguideConfig.minuteHeight*30;
+ timeline->DrawImage(cPoint(2, posY), *img);
+ textWidth = tvguideConfig.FontTimeLineTime->Width(timetext);
+ timeline->DrawText(cPoint((tvguideConfig.timeColWidth-textWidth)/2, posY + 5), timetext, colorFont, clrTransparent, tvguideConfig.FontTimeLineTime);
+ }
+ setTimeline();
+ delete img1;
+ delete img2;
+}
+
+cImage *cTimeLine::createBackgroundImage(int width, int height, tColor clrBgr, tColor clrBlend) {
+ cImage *image = new cImage(cSize(width, height));
+ image->Fill(clrBgr);
+ if (tvguideConfig.useBlending) {
+ int stepY = 0.5*height / 64;
+ int alpha = 0x00;
+ tColor clr;
+ for (int i = 0; i<64; i++) {
+ clr = AlphaBlend(clrBgr, clrBlend, alpha);
+ for (int y = i*stepY; y < (i+1)*stepY; y++) {
+ for (int x=0; x<width; x++) {
+ image->SetPixel(cPoint(x,y), clr);
+ }
+ }
+ alpha += 0x04;
+ }
+ }
+ return image;
+}
+
+void cTimeLine::setTimeline() {
+ int offset = myTime->GetTimelineOffset();
+ timeline->SetDrawPortPoint(cPoint(0, -offset*tvguideConfig.minuteHeight));
+}
+
+void cTimeLine::drawClock() {
+ cString currentTime = myTime->GetCurrentTime();
+ int textHeight = tvguideConfig.FontTimeLineTime->Height();
+ int clockWidth = tvguideConfig.FontTimeLineTime->Width(*currentTime);
+ clock->setColor(theme.Color(clrHeader), theme.Color(clrHeaderBlending));
+ clock->drawBackground();
+ clock->drawBorder();
+ clock->DrawText(cPoint((tvguideConfig.timeColWidth-clockWidth)/2, (tvguideConfig.footerHeight-textHeight)/2), *currentTime, theme.Color(clrFontHeader), clrTransparent, tvguideConfig.FontTimeLineTime);
+}
\ No newline at end of file diff --git a/timeline.h b/timeline.h new file mode 100644 index 0000000..e534fa5 --- /dev/null +++ b/timeline.h @@ -0,0 +1,22 @@ +#ifndef __TVGUIDE_TIMELINE_H
+#define __TVGUIDE_TIMELINE_H
+
+// --- cTimeLine -------------------------------------------------------------
+
+class cTimeLine {
+private:
+ cMyTime *myTime;
+ cStyledPixmap *dateViewer;
+ cPixmap *timeline;
+ cStyledPixmap *clock;
+ cImage *createBackgroundImage(int width, int height, tColor clrBgr, tColor clrBlend);
+public:
+ cTimeLine(cMyTime *myTime);
+ virtual ~cTimeLine(void);
+ void drawDateViewer();
+ void drawTimeline();
+ void setTimeline();
+ void drawClock();
+};
+
+#endif //__TVGUIDE_TIMELINE_H
\ No newline at end of file @@ -0,0 +1,106 @@ +#include "timer.h"
+
+cMyTime::~cMyTime(void) {
+}
+
+void cMyTime::Now() {
+ t = time(0);
+ tStart = t;
+ tStart = GetRounded();
+ tStop = tStart + (tvguideConfig.osdHeight - tvguideConfig.headerHeight - tvguideConfig.footerHeight)/tvguideConfig.minuteHeight*60;
+}
+
+void cMyTime::AddStep(int step) {
+ tStart += step*60;
+ tStop += step*60;
+}
+
+bool cMyTime::DelStep(int step) {
+ if ((tStart - step*60)+30*60 < t) {
+ return true;
+ }
+ tStart -= step*60;
+ tStop -= step*60;
+ return false;
+}
+
+void cMyTime::SetTime(time_t newTime) {
+ tStart = newTime;
+ tStop = tStart + (tvguideConfig.osdHeight - tvguideConfig.headerHeight - tvguideConfig.footerHeight)/tvguideConfig.minuteHeight*60;
+}
+
+time_t cMyTime::getPrevPrimetime(time_t current) {
+ tm *st = localtime(¤t);
+ if (st->tm_hour < 21) {
+ current -= 24 * 60* 60;
+ st = localtime(¤t);
+ }
+ st->tm_hour = 20;
+ st->tm_min = 0;
+ time_t primeTime = mktime(st);
+ return primeTime;
+}
+
+time_t cMyTime::getNextPrimetime(time_t current){
+ tm *st = localtime(¤t);
+ if (st->tm_hour > 19) {
+ current += 24 * 60* 60;
+ st = localtime(¤t);
+ }
+ st->tm_hour = 20;
+ st->tm_min = 0;
+ time_t primeTime = mktime(st);
+ return primeTime;
+}
+
+bool cMyTime::tooFarInPast(time_t current) {
+ if (current < t) {
+ return true;
+ }
+ return false;
+}
+
+cString cMyTime::GetCurrentTime() {
+ char buf[25];
+ t = time(0);
+ tm *st = localtime(&t);
+ //snprintf(text, sizeof(text), "%d:%02d", st->tm_hour, st->tm_min);
+ if (tvguideConfig.timeFormat == e12Hours) {
+ strftime(buf, sizeof(buf), "%I:%M %p", st);
+ } else if (tvguideConfig.timeFormat == e24Hours)
+ strftime(buf, sizeof(buf), "%H:%M", st);
+ return buf;
+
+}
+
+cString cMyTime::GetDate() {
+ char text[6];
+ tm *st = localtime(&tStart);
+ snprintf(text, sizeof(text), "%d.%d", st->tm_mday, st->tm_mon+1);
+ return text;
+}
+
+cString cMyTime::GetWeekday() {
+ return WeekDayName(tStart);
+}
+
+int cMyTime::GetTimelineOffset() {
+ tm *st = localtime(&tStart);
+ int offset = st->tm_hour*60;
+ offset += st->tm_min;
+ return offset;
+}
+
+time_t cMyTime::GetRounded() {
+ tm *rounded = localtime ( &tStart );
+ rounded->tm_sec = 0;
+ if (rounded->tm_min > 29)
+ rounded->tm_min = 30;
+ else
+ rounded->tm_min = 0;
+ return mktime(rounded);
+}
+
+void cMyTime::debug() {
+ esyslog("t: %s, tStart: %s, tStop: %s", *TimeString(t), *TimeString(tStart), *TimeString(tStop));
+}
@@ -0,0 +1,32 @@ +#ifndef __TVGUIDE_TIMER_H
+#define __TVGUIDE_TIMER_H
+
+// --- cMyTime -------------------------------------------------------------
+
+class cMyTime {
+ private:
+ time_t t;
+ time_t tStart;
+ time_t tStop;
+ public:
+ cMyTime(){};
+ virtual ~cMyTime(void);
+ void Now();
+ void AddStep(int step);
+ bool DelStep(int step);
+ void SetTime(time_t newTime);
+ time_t Get() {return t;};
+ time_t GetStart() {return tStart;};
+ time_t GetStop() {return tStop;};
+ cString GetCurrentTime();
+ cString GetDate();
+ cString GetWeekday();
+ time_t getPrevPrimetime(time_t current);
+ time_t getNextPrimetime(time_t current);
+ bool tooFarInPast(time_t current);
+ int GetTimelineOffset();
+ time_t GetRounded();
+ void debug();
+};
+
+#endif //__TVGUIDE_TIMER_H
\ No newline at end of file diff --git a/tvguide.c b/tvguide.c new file mode 100644 index 0000000..d513a62 --- /dev/null +++ b/tvguide.c @@ -0,0 +1,194 @@ +/* + * tvguide.c: A plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + * $Id$ + */ + +#include <time.h> +#include <getopt.h> +#include <vdr/osd.h> +#include <vdr/plugin.h> +#include <vdr/device.h> + +#include "tvguideosd.c" + +#if defined(APIVERSNUM) && APIVERSNUM < 10717 +#error "VDR-1.7.17 API version or greater is required!" +#endif + + + +static const char *VERSION = "0.0.1"; +static const char *DESCRIPTION = "A fancy 2d EPG Viewer"; +static const char *MAINMENUENTRY = "Tvguide"; + +class cPluginTvguide : public cPlugin { +private: + bool logoPathSet; + bool imagesPathSet; +public: + cPluginTvguide(void); + virtual ~cPluginTvguide(); + 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 MAINMENUENTRY; } + 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); + }; + +cPluginTvguide::cPluginTvguide(void) +{ + // Initialize any member variables here. + // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL + // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! + logoPathSet = false; + imagesPathSet = false; +} + +cPluginTvguide::~cPluginTvguide() +{ + // Clean up after yourself! +} + +const char *cPluginTvguide::CommandLineHelp(void) +{ + // Return a string that describes all known command line options. + return + " -i <IMAGESDIR>, --epgimages=<IMAGESDIR> Set directory where epgimages are stored\n" + " -l <LOGODIR>, --logodir=<LOGODIR> Set directory where logos are stored.\n"; +} + +bool cPluginTvguide::ProcessArgs(int argc, char *argv[]) +{ + // Implement command line argument processing here if applicable. + static const struct option long_options[] = { + { "epgimages", required_argument, NULL, 'i' }, + { "logopath", required_argument, NULL, 'l' }, + { 0, 0, 0, 0 } + }; + + int c; + cString *path = NULL; + while ((c = getopt_long(argc, argv, "i:f:l:", long_options, NULL)) != -1) { + switch (c) { + case 'i': + path = new cString(optarg); + tvguideConfig.SetImagesPath(*path); + imagesPathSet = true; + break; + case 'l': + path = new cString(optarg); + tvguideConfig.SetLogoPath(*path); + logoPathSet = true; + break; + default: + return false; + } + if (path) + delete path; + } + return true; +} + +bool cPluginTvguide::Initialize(void) +{ + // Initialize any background activities the plugin shall perform. + return true; +} + +bool cPluginTvguide::Start(void) +{ + if (!logoPathSet) { + cString path = cString::sprintf("%s/channellogos/", cPlugin::ConfigDirectory(PLUGIN_NAME_I18N)); + tvguideConfig.SetLogoPath(path); + logoPathSet = true; + } + + if (!imagesPathSet) { + cString path = cString::sprintf("%s/epgimages/", cPlugin::ConfigDirectory(PLUGIN_NAME_I18N)); + tvguideConfig.SetImagesPath(path); + logoPathSet = true; + } + return true; +} + +void cPluginTvguide::Stop(void) +{ + // Stop any background activities the plugin is performing. +} + +void cPluginTvguide::Housekeeping(void) +{ + // Perform any cleanup or other regular tasks. +} + +void cPluginTvguide::MainThreadHook(void) +{ + // Perform actions in the context of the main program thread. + // WARNING: Use with great care - see PLUGINS.html! +} + +cString cPluginTvguide::Active(void) +{ + // Return a message string if shutdown should be postponed + return NULL; +} + +time_t cPluginTvguide::WakeupTime(void) +{ + // Return custom wakeup time for shutdown script + return 0; +} + +cOsdObject *cPluginTvguide::MainMenuAction(void) +{ + // Perform the action when selected from the main VDR menu. + return new cTvGuideOsd; +} + +cMenuSetupPage *cPluginTvguide::SetupMenu(void) +{ + // Return a setup menu in case the plugin supports one. + return new cTvguideSetup(); +} + +bool cPluginTvguide::SetupParse(const char *Name, const char *Value) +{ + // Parse your own setup parameters and store their values. + return tvguideConfig.SetupParse(Name, Value); +} + +bool cPluginTvguide::Service(const char *Id, void *Data) +{ + // Handle custom service requests from other plugins + return false; +} + +const char **cPluginTvguide::SVDRPHelpPages(void) +{ + // Return help text for SVDRP commands this plugin implements + return NULL; +} + +cString cPluginTvguide::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode) +{ + // Process SVDRP commands this plugin implements + return NULL; +} + +VDRPLUGINCREATOR(cPluginTvguide); // Don't touch this! diff --git a/tvguideosd.c b/tvguideosd.c new file mode 100644 index 0000000..8fca65a --- /dev/null +++ b/tvguideosd.c @@ -0,0 +1,541 @@ +// --- Theme -------------------------------------------------------------
+static cTheme theme;
+
+THEME_CLR(theme, clrBackgroundOSD, clrBlack);
+THEME_CLR(theme, clrBackground, clrBlack);
+THEME_CLR(theme, clrGrid1, 0xFF404749);
+THEME_CLR(theme, clrGrid1Blending, 0xFF000000);
+THEME_CLR(theme, clrGrid2, 0xFF20293F);
+THEME_CLR(theme, clrGrid2Blending, 0xFF000000);
+THEME_CLR(theme, clrHighlight, 0xFFFF4D00);
+THEME_CLR(theme, clrHighlightBlending, 0xFF000000);
+THEME_CLR(theme, clrFont, clrWhite);
+THEME_CLR(theme, clrFontHeader, clrWhite);
+THEME_CLR(theme, clrFontButtons, clrWhite);
+THEME_CLR(theme, clrHeader, clrBlack);
+THEME_CLR(theme, clrHeaderBlending, 0xFFE0E0E0);
+THEME_CLR(theme, clrBorder, clrWhite);
+THEME_CLR(theme, clrTimeline1, clrWhite);
+THEME_CLR(theme, clrTimeline1Blending, 0xFF828282);
+THEME_CLR(theme, clrTimeline2, clrBlack);
+THEME_CLR(theme, clrTimeline2Blending, 0xFF3F3F3F);
+THEME_CLR(theme, clrButtonRed, 0xFFD42627);
+THEME_CLR(theme, clrButtonRedBlending, 0xFFE0E0E0);
+THEME_CLR(theme, clrButtonGreen, 0xFF004F00);
+THEME_CLR(theme, clrButtonGreenBlending, 0xFFE0E0E0);
+THEME_CLR(theme, clrButtonYellow, 0xFFffa300);
+THEME_CLR(theme, clrButtonYellowBlending, 0xFFE0E0E0);
+THEME_CLR(theme, clrButtonBlue, 0xFF0000fe);
+THEME_CLR(theme, clrButtonBlueBlending, 0xFFE0E0E0);
+
+#include "config.c"
+cTvguideConfig tvguideConfig;
+
+#include "osdmanager.c"
+cOsdManager osdManager;
+
+#include "setup.c"
+#include "imageloader.c"
+#include "styledpixmap.c"
+#include "timer.c"
+#include "messagebox.c"
+#include "timeline.c"
+#include "epggrid.c"
+#include "detailview.c"
+#include "channelcolumn.c"
+#include "footer.c"
+
+#include "tvguideosd.h"
+#include <stdlib.h>
+
+cTvGuideOsd::cTvGuideOsd(void) {
+ detailView = NULL;
+ detailViewActive = false;
+ timeLine = NULL;
+}
+
+cTvGuideOsd::~cTvGuideOsd() {
+ delete myTime;
+ columns.Clear();
+ if (detailView)
+ delete detailView;
+ delete timeLine;
+ delete footer;
+ cMessageBox::Destroy();
+ osdManager.deleteOsd();
+}
+
+void cTvGuideOsd::Show(void) {
+ int start = cTimeMs::Now();
+ bool ok = false;
+ ok = osdManager.setOsd();
+ if (ok) {
+ tvguideConfig.setDynamicValues(osdManager.Width(), osdManager.Height());
+ tvguideConfig.loadTheme();
+ osdManager.setBackground();
+ myTime = new cMyTime();
+ myTime->Now();
+ drawOsd();
+ }
+ esyslog("tvguide: Rendering took %d ms", int(cTimeMs::Now()-start));
+}
+
+void cTvGuideOsd::drawOsd() {
+ cPixmap::Lock();
+ cChannel *startChannel = Channels.GetByNumber(cDevice::CurrentChannel());
+ timeLine = new cTimeLine(myTime);
+ timeLine->drawDateViewer();
+ timeLine->drawTimeline();
+ timeLine->drawClock();
+ footer = new cFooter();
+ footer->drawRedButton();
+ footer->drawGreenButton();
+ footer->drawYellowButton();
+ footer->drawBlueButton();
+ osdManager.flush();
+ readChannels(startChannel);
+ drawGridsChannelJump();
+ osdManager.flush();
+ cPixmap::Unlock();
+}
+
+void cTvGuideOsd::readChannels(cChannel *channelStart) {
+ int i=0;
+ columns.Clear();
+ if (!channelStart)
+ return;
+ for (cChannel *channel = channelStart; channel; channel = Channels.Next(channel)) {
+ if (!channel->GroupSep()) {
+ cChannelColumn *column = new cChannelColumn(i, channel, myTime);
+ if (column->readGrids()) {
+ columns.Add(column);
+ i++;
+ } else {
+ delete column;
+ }
+ }
+ if (i == tvguideConfig.channelCols)
+ break;
+ }
+}
+
+bool cTvGuideOsd::readChannelsReverse(cChannel *channelStart) {
+ bool doUpdate = false;
+ int i = tvguideConfig.channelCols;
+ if (!channelStart)
+ return false;
+ for (cChannel *channel = Channels.Prev(channelStart); channel; channel = Channels.Prev(channel)) {
+ if (!channel->GroupSep()) {
+ cChannelColumn *column = new cChannelColumn(i-1, channel, myTime);
+ if (column->readGrids()) {
+ if (i == tvguideConfig.channelCols) {
+ columns.Clear();
+ doUpdate = true;
+ }
+ columns.Ins(column, columns.First());
+ i--;
+ } else {
+ delete column;
+ }
+ }
+ if (i == 0)
+ break;
+ }
+ return doUpdate;
+}
+
+void cTvGuideOsd::drawGridsChannelJump() {
+ if (columns.Count() == 0)
+ return;
+ activeGrid = columns.First()->getActive();
+ if (activeGrid)
+ activeGrid->SetActive();
+ for (cChannelColumn *column = columns.First(); column; column = columns.Next(column)) {
+ column->createHeader();
+ column->drawGrids();
+ }
+}
+
+void cTvGuideOsd::drawGridsTimeJump() {
+ if (columns.Count() == 0)
+ return;
+ cChannelColumn *colActive = NULL;
+ if (activeGrid) {
+ colActive = activeGrid->column;
+ } else {
+ colActive = columns.First();
+ }
+ for (cChannelColumn *column = columns.First(); column; column = columns.Next(column)) {
+ column->clearGrids();
+ column->readGrids();
+ column->drawGrids();
+ }
+ activeGrid = colActive->getActive();
+ if (activeGrid) {
+ activeGrid->SetActive();
+ activeGrid->Draw();
+ }
+}
+
+void cTvGuideOsd::setNextActiveGrid(cEpgGrid *next) {
+ if (!next || !activeGrid) {
+ return;
+ }
+ activeGrid->SetInActive();
+ activeGrid->Draw();
+ activeGrid = next;
+ activeGrid->SetActive();
+ activeGrid->Draw();
+}
+
+void cTvGuideOsd::processKeyUp() {
+ if (detailViewActive) {
+ detailView->scrollUp();
+ } else {
+ if (activeGrid == NULL) {
+ ScrollBack();
+ //Search for new active Grid
+ cEpgGrid *actGrid = NULL;
+ for (cChannelColumn *column = columns.First(); column; column = columns.Next(column)) {
+ actGrid = column->getActive();
+ if (actGrid) {
+ activeGrid = actGrid;
+ activeGrid->SetActive();
+ activeGrid->Draw();
+ break;
+ }
+ }
+ } else if (activeGrid->StartTime() <= myTime->GetStart()) {
+ activeGrid->debug();
+ ScrollBack();
+ } else {
+ cEpgGrid *prev = NULL;
+ prev = activeGrid->column->getPrev(activeGrid);
+ if (prev) {
+ setNextActiveGrid(prev);
+ } else {
+ ScrollBack();
+ prev = activeGrid->column->getPrev(activeGrid);
+ if (prev) {
+ setNextActiveGrid(prev);
+ }
+ }
+ }
+ }
+ osdManager.flush();
+}
+
+void cTvGuideOsd::processKeyDown() {
+ if (detailViewActive) {
+ detailView->scrollDown();
+ } else {
+ if (activeGrid == NULL) {
+ ScrollForward();
+ } else if (activeGrid->EndTime() > myTime->GetStop()) {
+ ScrollForward();
+ } else {
+ cEpgGrid *next = NULL;
+ next = activeGrid->column->getNext(activeGrid);
+ if (next) {
+ setNextActiveGrid(next);
+ } else {
+ ScrollForward();
+ next = activeGrid->column->getNext(activeGrid);
+ if (next) {
+ setNextActiveGrid(next);
+ }
+ }
+ }
+ }
+ osdManager.flush();
+}
+
+void cTvGuideOsd::ScrollForward() {
+ myTime->AddStep(tvguideConfig.stepMinutes);
+ timeLine->drawDateViewer();
+ timeLine->drawClock();
+ timeLine->setTimeline();
+ for (cChannelColumn *column = columns.First(); column; column = columns.Next(column)) {
+ column->AddNewGridsAtEnd();
+ column->ClearOutdatedStart();
+ column->drawGrids();
+ }
+}
+
+void cTvGuideOsd::ScrollBack() {
+ bool tooFarInPast = myTime->DelStep(tvguideConfig.stepMinutes);
+ if (tooFarInPast)
+ return;
+ timeLine->drawDateViewer();
+ timeLine->drawClock();
+ timeLine->setTimeline();
+ for (cChannelColumn *column = columns.First(); column; column = columns.Next(column)) {
+ column->AddNewGridsAtStart();
+ column->ClearOutdatedEnd();
+ column->drawGrids();
+ }
+}
+
+void cTvGuideOsd::processKeyLeft() {
+ if (detailViewActive)
+ return;
+ if (activeGrid == NULL)
+ return;
+ cChannelColumn *colLeft = columns.Prev(activeGrid->column);
+ if (!colLeft) {
+ cChannel *channelLeft = activeGrid->column->getChannel();
+ while (channelLeft = Channels.Prev(channelLeft)) {
+ if (!channelLeft->GroupSep()) {
+ colLeft = new cChannelColumn(0, channelLeft, myTime);
+ if (colLeft->readGrids()) {
+ break;
+ } else {
+ delete colLeft;
+ colLeft = NULL;
+ }
+ }
+ }
+ if (colLeft) {
+ if (columns.Count() == tvguideConfig.channelCols) {
+ cChannelColumn *cLast = columns.Last();
+ columns.Del(cLast);
+ }
+ for (cChannelColumn *column = columns.First(); column; column = columns.Next(column)) {
+ column->SetNum(column->GetNum() + 1);
+ column->drawHeader();
+ column->drawGrids();
+ }
+ columns.Ins(colLeft, columns.First());
+ colLeft->createHeader();
+ colLeft->drawGrids();
+ }
+ }
+
+ if (colLeft) {
+ cEpgGrid *left = colLeft->getNeighbor(activeGrid);
+ if (left) {
+ setNextActiveGrid(left);
+ }
+ }
+ osdManager.flush();
+}
+
+void cTvGuideOsd::processKeyRight() {
+ if (detailViewActive)
+ return;
+ if (activeGrid == NULL)
+ return;
+ cChannelColumn *colRight = columns.Next(activeGrid->column);
+ if (!colRight) {
+ cChannel *channelRight = activeGrid->column->getChannel();
+ while (channelRight = Channels.Next(channelRight)) {
+ if (!channelRight->GroupSep()) {
+ colRight = new cChannelColumn(tvguideConfig.channelCols - 1, channelRight, myTime);
+ if (colRight->readGrids()) {
+ break;
+ } else {
+ delete colRight;
+ colRight = NULL;
+ }
+ }
+ }
+ if (colRight) {
+ if (columns.Count() == tvguideConfig.channelCols) {
+ cChannelColumn *cFirst = columns.First();
+ columns.Del(cFirst);
+ }
+ for (cChannelColumn *column = columns.First(); column; column = columns.Next(column)) {
+ column->SetNum(column->GetNum() - 1);
+ column->drawHeader();
+ column->drawGrids();
+ }
+ columns.Add(colRight);
+ colRight->createHeader();
+ colRight->drawGrids();
+ }
+ }
+ if (colRight) {
+ cEpgGrid *right = colRight->getNeighbor(activeGrid);
+ if (right) {
+ setNextActiveGrid(right);
+ }
+ }
+ osdManager.flush();
+}
+
+void cTvGuideOsd::processKeyOk() {
+ if (detailViewActive) {
+ delete detailView;
+ detailView = NULL;
+ detailViewActive = false;
+ osdManager.flush();
+ } else {
+ detailViewActive = true;
+ detailView = new cDetailView(activeGrid);
+ detailView->Start();
+ }
+}
+
+void cTvGuideOsd::processKeyRed() {
+ if (activeGrid == NULL)
+ return;
+ cTimer *timer = new cTimer(activeGrid->GetEvent());
+ cTimer *t = Timers.GetTimer(timer);
+ cString msg;
+ if (t) {
+ isyslog("timer %s already exists", *timer->ToDescr());
+ delete timer;
+ msg = cString::sprintf(tr("Timer not set! There is already a timer for this item."));
+ } else {
+ Timers.Add(timer);
+ Timers.SetModified();
+ msg = cString::sprintf("%s:\n%s (%s) %s - %s", tr("Timer set"), activeGrid->GetEvent()->Title(), timer->Channel()->Name(), *DayDateTime(timer->StartTime()), *TimeString(timer->StopTime()));
+ timer->SetEvent(activeGrid->GetEvent());
+ activeGrid->setTimer();
+ activeGrid->column->setTimer();
+ activeGrid->SetDirty();
+ activeGrid->Draw();
+ osdManager.flush();
+ isyslog("timer %s added (active)", *timer->ToDescr());
+ }
+ cMessageBox::Start(4000, msg);
+}
+
+void cTvGuideOsd::processKeyGreen() {
+ if (activeGrid == NULL)
+ return;
+ cChannel *currentChannel = activeGrid->column->getChannel();
+ bool doUpdate = readChannelsReverse(currentChannel);
+ if (doUpdate && (columns.Count() > 0)) {
+ drawGridsChannelJump();
+ }
+ osdManager.flush();
+}
+
+void cTvGuideOsd::processKeyYellow() {
+ if (activeGrid == NULL)
+ return;
+ cChannel *currentChannel = activeGrid->column->getChannel();
+ cChannel *next = NULL;
+ int i=0;
+ for (cChannel *channel = currentChannel; channel; channel = Channels.Next(channel)) {
+ if (!channel->GroupSep()) {
+ next = channel;
+ i++;
+ }
+ if (i == (tvguideConfig.jumpChannels+1))
+ break;
+ }
+ if (next) {
+ readChannels(next);
+ if (columns.Count() > 0) {
+ drawGridsChannelJump();
+ }
+ osdManager.flush();
+ }
+}
+
+eOSState cTvGuideOsd::processKeyBlue() {
+ if (activeGrid == NULL)
+ return osContinue;
+ cChannel *currentChannel = activeGrid->column->getChannel();
+ if (currentChannel) {
+ cDevice::PrimaryDevice()->SwitchChannel(currentChannel, true);
+ return osEnd;
+ }
+ return osContinue;
+}
+
+void cTvGuideOsd::processKey1() {
+ bool tooFarInPast = myTime->DelStep(tvguideConfig.bigStepHours*60);
+ if (tooFarInPast)
+ return;
+ drawGridsTimeJump();
+ timeLine->drawDateViewer();
+ timeLine->drawClock();
+ timeLine->setTimeline();
+ osdManager.flush();
+}
+
+void cTvGuideOsd::processKey3() {
+ myTime->AddStep(tvguideConfig.bigStepHours*60);
+ drawGridsTimeJump();
+ timeLine->drawDateViewer();
+ timeLine->drawClock();
+ timeLine->setTimeline();
+ osdManager.flush();
+}
+
+void cTvGuideOsd::processKey4() {
+ bool tooFarInPast = myTime->DelStep(tvguideConfig.hugeStepHours*60);
+ if (tooFarInPast)
+ return;
+ drawGridsTimeJump();
+ timeLine->drawDateViewer();
+ timeLine->drawClock();
+ timeLine->setTimeline();
+ osdManager.flush();
+}
+
+void cTvGuideOsd::processKey6() {
+ myTime->AddStep(tvguideConfig.hugeStepHours*60);
+ drawGridsTimeJump();
+ timeLine->drawDateViewer();
+ timeLine->drawClock();
+ timeLine->setTimeline();
+ osdManager.flush();
+}
+
+void cTvGuideOsd::processKey7() {
+ cMyTime *primeChecker = new cMyTime();
+ primeChecker->Now();
+ time_t prevPrime = primeChecker->getPrevPrimetime(myTime->GetStart());
+ if (primeChecker->tooFarInPast(prevPrime))
+ return;
+ myTime->SetTime(prevPrime);
+ drawGridsTimeJump();
+ timeLine->drawDateViewer();
+ timeLine->drawClock();
+ timeLine->setTimeline();
+ osdManager.flush();
+}
+
+void cTvGuideOsd::processKey9() {
+ cMyTime *primeChecker = new cMyTime();
+ time_t nextPrime = primeChecker->getNextPrimetime(myTime->GetStart());
+ myTime->SetTime(nextPrime);
+ drawGridsTimeJump();
+ timeLine->drawDateViewer();
+ timeLine->drawClock();
+ timeLine->setTimeline();
+ osdManager.flush();
+}
+
+eOSState cTvGuideOsd::ProcessKey(eKeys Key) {
+ eOSState state = cOsdObject::ProcessKey(Key);
+ if (state == osUnknown) {
+ cPixmap::Lock();
+ state = osContinue;
+ switch (Key & ~k_Repeat) {
+ case kUp: processKeyUp(); break;
+ case kDown: processKeyDown(); break;
+ case kLeft: processKeyLeft(); break;
+ case kRight: processKeyRight(); break;
+ case kRed: processKeyRed(); break;
+ case kGreen: processKeyGreen(); break;
+ case kYellow: processKeyYellow(); break;
+ case kBlue: state = processKeyBlue(); break;
+ case kOk: processKeyOk(); break;
+ case kBack: state=osEnd; break;
+ case k1: processKey1(); break;
+ case k3: processKey3(); break;
+ case k4: processKey4(); break;
+ case k6: processKey6(); break;
+ case k7: processKey7(); break;
+ case k9: processKey9(); break;
+ default: break;
+ }
+ cPixmap::Unlock();
+ }
+ return state;
+}
\ No newline at end of file diff --git a/tvguideosd.h b/tvguideosd.h new file mode 100644 index 0000000..c619ec4 --- /dev/null +++ b/tvguideosd.h @@ -0,0 +1,45 @@ +#ifndef __TVGUIDE_TVGUIDEOSD_H
+#define __TVGUIDE_TVGUIDEOSD_H
+
+// --- cTvGuideOsd -------------------------------------------------------------
+
+class cTvGuideOsd : public cOsdObject {
+private:
+ cMyTime *myTime;
+ cList<cChannelColumn> columns;
+ cEpgGrid *activeGrid;
+ cDetailView *detailView;
+ cTimeLine *timeLine;
+ cFooter *footer;
+ bool detailViewActive;
+ void drawOsd();
+ void readChannels(cChannel *channelStart);
+ bool readChannelsReverse(cChannel *channelStart);
+ void drawGridsChannelJump();
+ void drawGridsTimeJump();
+ void processKeyUp();
+ void processKeyDown();
+ void processKeyLeft();
+ void processKeyRight();
+ void processKeyRed();
+ void processKeyGreen();
+ void processKeyYellow();
+ eOSState processKeyBlue();
+ void processKeyOk();
+ void processKey1();
+ void processKey3();
+ void processKey4();
+ void processKey6();
+ void processKey7();
+ void processKey9();
+ void setNextActiveGrid(cEpgGrid *next);
+ void ScrollForward();
+ void ScrollBack();
+public:
+ cTvGuideOsd(void);
+ virtual ~cTvGuideOsd(void);
+ virtual void Show(void);
+ virtual eOSState ProcessKey(eKeys Key);
+};
+
+#endif //__TVGUIDE_TVGUIDEOSD_H
\ No newline at end of file |