summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlordjaxom <lordjaxom>2004-05-23 00:35:46 +0000
committerlordjaxom <lordjaxom>2004-05-23 00:35:46 +0000
commitd309055320433e5fd899de53dc688d679609e6db (patch)
treeee3c3c97b3881f1e35e0da745b9571d11c0b6ac2
downloadvdr-plugin-text2skin-d309055320433e5fd899de53dc688d679609e6db.tar.gz
vdr-plugin-text2skin-d309055320433e5fd899de53dc688d679609e6db.tar.bz2
- Initial revision.v0.0.1-pre1
-rw-r--r--COPYING340
-rw-r--r--HISTORY6
-rw-r--r--Makefile90
-rw-r--r--README11
-rw-r--r--SKINS314
-rw-r--r--bitmap.c63
-rw-r--r--bitmap.h22
-rw-r--r--common.c71
-rw-r--r--common.h14
-rw-r--r--data.c196
-rw-r--r--data.h125
-rw-r--r--display.c236
-rw-r--r--display.h95
-rw-r--r--loader.c79
-rw-r--r--loader.h32
-rw-r--r--render.c370
-rw-r--r--render.h98
-rw-r--r--text2skin.c51
18 files changed, 2213 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..5b6e7c6
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library General
+Public License instead of this License.
diff --git a/HISTORY b/HISTORY
new file mode 100644
index 0000000..57ce90c
--- /dev/null
+++ b/HISTORY
@@ -0,0 +1,6 @@
+VDR Plugin 'text2skin' Revision History
+---------------------------------------
+
+2004-05-21: Version 0.0.1
+
+- Initial revision.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..ccd1e75
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,90 @@
+#
+# Makefile for a Video Disk Recorder plugin
+#
+# $Id: Makefile,v 1.1.1.1 2004/05/23 00:08:03 lordjaxom Exp $
+
+# disable in case you don't want to install imlib
+# in that case, you will not be able to load other files than simple xpms
+HAVE_IMLIB=1
+
+# 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 = text2skin
+
+### 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 ?= -O2 -Wall -Woverloaded-virtual
+
+### The directory environment:
+
+DVBDIR = ../../../../DVB
+VDRDIR = ../../..
+LIBDIR = ../../lib
+TMPDIR = /tmp
+
+### Allow user defined options to overwrite defaults:
+
+-include $(VDRDIR)/Make.config
+
+### The version number of VDR (taken from VDR's "config.h"):
+
+VDRVERSION = $(shell grep 'define VDRVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g')
+
+### The name of the distribution archive:
+
+ARCHIVE = $(PLUGIN)-$(VERSION)
+PACKAGE = vdr-$(ARCHIVE)
+
+### Includes and Defines (add further entries here):
+
+ifdef HAVE_IMLIB
+ DEFINES += -DHAVE_IMLIB
+endif
+
+INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include
+
+DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
+
+### The object files (add further files here):
+
+OBJS = $(PLUGIN).o loader.o data.o display.o render.o common.o bitmap.o
+
+### Implicit rules:
+
+%.o: %.c
+ $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+
+# Dependencies:
+
+MAKEDEP = g++ -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+### Targets:
+
+all: libvdr-$(PLUGIN).so
+
+libvdr-$(PLUGIN).so: $(OBJS)
+ $(CXX) $(CXXFLAGS) -shared $(OBJS) -lImlib2 -o $@
+ @cp $@ $(LIBDIR)/$@.$(VDRVERSION)
+
+dist: 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* *~
diff --git a/README b/README
new file mode 100644
index 0000000..4e04b83
--- /dev/null
+++ b/README
@@ -0,0 +1,11 @@
+This is a "plugin" for the Video Disk Recorder (VDR).
+
+Written by: Your Name <email@host.dom>
+
+Project's homepage: URL
+
+Latest version available at: URL
+
+See the file COPYING for license information.
+
+Description:
diff --git a/SKINS b/SKINS
new file mode 100644
index 0000000..d1628ca
--- /dev/null
+++ b/SKINS
@@ -0,0 +1,314 @@
+
+How To create text-based skins
+------------------------------
+
+[ TODO remove this ]
+You may encounter bracketed phrases in this document. Please ignore them, they
+are comments for me which will be removed in official release versions.
+
+[ TODO move this to manual ]
+The Skin itself is located in a subdirectory "text2skin" inside the "plugins"
+directory of your VDR configuration directory. This usually is the video
+directory, if you didn't specify -c on the commandline. If you did, the
+subdirectory is located there. Each skin has an own subdirectory there, which
+holds the skin description file and the needed image files. The skin
+description file must have the same name as the skin directory, with the
+extension ".skin"
+
+Example:
+/video0/plugins/text2skin
+/video0/plugins/text2skin/myskin
+/video0/plugins/text2skin/msykin/msykin.skin
+/video0/plugins/text2skin/myskin/channeldisplay.png
+
+It is important that you understand the limitations of the OSD memory. If there
+are too many objects with too many colors defined, VDR will throw an error and
+some areas will not be displayed. For other output devices this limitations may
+not apply, so if you are planning to design a skin for another output device,
+feel free to use more colors, but remember that VDR can handle a maximum of 256
+areas per object.
+
+An object is defined to be a specific area with a specific palette and color
+depth. Those objects will be referred to as 'backgrounds' later on. Calculate
+the dimensions of them wisely, since overlapping areas or oversized areas will
+lead to an error. Also, the widht and height of each area has to be a multiple
+of four [ TODO may not apply to different output devices ].
+
+
+Creation of an image
+--------------------
+
+I used gimp to create some test images displaying things on screen, although
+I don't know much about image processing :-). To give an advice, I will point
+out how I created those test images with GIMP.
+
+I've used a template for a menu provided by a community member, tiled it into
+sections fully covered by the image. That made three images in this case. Then
+I added a little bit of transparency to the image covering the middle part. I've
+resized the image so that it's width and height were multiples of four. Now I've
+added 50% transparency to the top layer of the image. Then I've reduced the
+colordepth of the image (Image->Mode->Indexed) to 14 colors (of course the
+image may not be too extensive, but 14 colors can give some nice gradients).
+That leaves two colors for text and progress bar in the same display. Reduce
+the number of colors according to the background depth and additional
+decoration you intend to use. I saved the results to a png file and placed the
+result into the skin.
+
+If you intend to use xpm's, be aware that VDR doesn't know about named colors,
+so most images GIMP creates will not be read on-the-fly, because GIMP always
+uses the color "None". [ TODO at least None will be supported by VDR 1.3.8 ]
+
+
+The Description File Format
+---------------------------
+
+It is a simple configuration file, consisting of Sections and items.
+Commentary lines can be added when they are lead in by a '#'. Blank lines will
+be ignored. A section is placed in '[]' brackets. An item is lead in by an
+'Item=object' phrase.
+
+Example:
+Item=Skin,name=Test,version=0.0.1;
+[Channel]
+Item=Background,path=channeltop.xpm,x=42,y=350,width=540,height=32,bg=#00FFFFFF;
+Item=Background,path=channel.png,x=48,y=382,width=528,height=84;
+Item=ChannelNumberName,x=50,y=355,fg=#FFFFFFFF,bg=#FF1965FF,font=Sml;
+Item=PresentTime,x=52,y=387,fg=#FFFFFFFF,bg=#7F002254,font=Osd;
+[Volume]
+Item=Background,x=10,y=10,width=10,height=100;
+Item=Volumebar,x=10,y=10,width=10,height=100,bg=#FF000000,fg=#FFFFFFFF;
+
+
+Known Sections
+--------------
+
+Section: [Channel]
+Description: The channel display. It displays the current programme and number,
+ together with the currently running programme and possibly a
+ timebar and (not implemented yet) channel logo [ TODO remove
+ comment ].
+
+Section: [Volume]
+Description: The volume display. It displays the volumebar and possibly a mute
+ symbol, along with decorative items.
+
+Section: [ReplayMode]
+Description: The replay modes display. Will be shown if only the replay mode
+ symbol shall be shown.
+
+Section: [Replay]
+Description: [ TODO ] Full replay display.
+
+Section: [Message]
+Description: [ TODO ] Message only display.
+
+Section: [Menu]
+Description: [ TODO ] Full menu.
+
+
+Known Items
+-----------
+Item: Item=Skin
+Description: This identifies the skin and adds a description to it.
+Parameters: name, version
+
+Item: Item=Background
+Description: This adds a background area for the specific display. This area
+ will be used to draw anything else, so you have to define a
+ background for everything that will be drawn later on. You can
+ define a background image for that area here, too. That picture
+ has to be the same width and height as the area. If you don't use
+ a background image, the area will not be initialized with any
+ content. The background color will replace the color 0 in the
+ images palette, and the foreground color will replace color 1.
+Parameters: x, y, width, height, bpp, path, bg, fg
+
+Item: Item=Text
+Description: Draws plain text into the given area, using the given foreground
+ color. The background color is ignored, so no initializing
+ rectangle will be drawn. If no width or height are given, the
+ limits are the background areas.
+Parameters: x, y, text, width, height, fg, font, align
+
+
+Item: Item=DateTime
+Description: Draws a date and time string into the given area. Otherwise, see
+ Item=Text
+Parameters: x, y, width, height, fg, font, align
+
+Item: Item=Date
+Description: Draws a date string into the given area. Otherwise, see Item=Text
+Parameters: x, y, width, height, fg, font, align
+
+Item: Item=Time
+Description: Draws a time string into the given area. Otherwise, see Item=Text
+Parameters: x, y, width, height, fg, font, align
+
+Item: Item=ChannelNumberName
+Description: Draws the channel number and name into the given area. Otherwise,
+ see Item=Text
+Parameters: x, y, width, height, fg, font, align
+
+Item: Item=ChannelNumber
+Description: Draws the channel number into the given area. Otherwise, see
+ Item=Text
+Parameters: x, y, width, height, fg, font, align
+
+Item: Item=ChannelName
+Description: Draws the channel name into the given area. Otherwise, see
+ Item=Text
+Parameters: x, y, width, height, fg, font, align
+
+Item: Item=Rectangle
+Description: Draws a filled rectangle into the defined area.
+Parameters: x, y, width, height, fg
+
+Item: Item=Ellipse
+Description: Draws a filled ellipse or a part of an ellipse into the defined
+ area.
+Parameters: x, y, width, height, fg
+
+Item: Item=Timebar
+Description: Draws a timebar displaying the progress of the current programme.
+ The area will be filled with the background color and the bar will
+ be drawn using the foreground color. If width is greater than
+ height, the bar will be drawn vertically, otherwise horizontally.
+Parameters: x, y, width, height, fg, bg
+
+Item: Item=PresentTime
+Description: Draws the start time of the present programme.
+Parameters: x, y, width, height, fg, font, align
+
+Item: Item=PresentTitle
+Description: Draws the title of the present programme.
+Parameters: x, y, width, height, fg, font, align
+
+Item: Item=PresentShortText
+Description: Draws the short text (or episode name) of the present programme.
+Parameters: x, y, width, height, fg, font, align
+
+Item: Item=FollowingTime
+Description: Draws the start time of the following programme.
+Parameters: x, y, width, height, fg, font, align
+
+Item: Item=FollowingTitle
+Description: Draws the title of the following programme.
+Parameters: x, y, width, height, fg, font, align
+
+Item: Item=FollowingShortText
+Description: Draws the short text (or episode name) of the following programme.
+Parameters: x, y, width, height, fg, font, align
+
+Item: Item=SymbolTeletext
+Description: Draws the specified image into the specified location if the
+ current channel has teletext. If that is not the case, the
+ alternative image (if given) will be displayed. For details on the
+ image handling, see Item=Background.
+Parameters: x, y, width, height, path, altpath, fg, bg
+
+Item: Item=SymbolAudio
+Description: Draws the specified image into the specified location if the
+ current channel has multiple languages. If that is not the case,
+ the alternative image (if given) will be displayed. For details on
+ the image handling, see Item=Background.
+Parameters: x, y, width, height, path, altpath, fg, bg
+
+Item: Item=SymbolDolby
+Description: Draws the specified image into the specified location if the
+ current channel has ac3 sound. If that is not the case, the
+ alternative image (if given) will be displayed. For details on the
+ image handling, see Item=Background.
+Parameters: x, y, width, height, path, altpath, fg, bg
+
+Item: Item=SymbolEncrypted
+Description: Draws the specified image into the specified location if the
+ current channel is encrypted. If that is not the case, the
+ alternative image (if given) will be displayed. For details on the
+ image handling, see Item=Background.
+Parameters: x, y, width, height, path, altpath, fg, bg
+
+Item: Item=Volumebar
+Description: Draws a volumebar into the specified area. For more details, see
+ Item=Timebar.
+Parameters: x, y, width, height, fg, bg
+
+Item: Item=Mute
+Description: Draws a mute symbol and/or text (if given) into the specified area.
+ See Item=Text and Item=Background for more on text and image
+ handling.
+Parameters: x, y, width, height, fg, bg, text, font, align, path
+
+Item: Item=Progressbar
+Description: Draws a progressbar displaying the replay progress into the
+ specified area. For more details, see Item=Timebar.
+Parameters: x, y, width, height, fg, bg
+
+Item: Item=ReplayTitle
+Description: Draws the title of the current replay.
+Parameters: x, y, width, height, fg, font, align
+
+
+Known Parameters
+----------------
+
+Parameter: x
+Description: A positive number representing the vertical offset in pixels.
+Default: MANDATORY
+
+Parameter: y
+Description: A positive number representing the horizontal offset in pixels.
+Default: MANDATORY
+
+Parameter: width
+Description: A positive number representing the width in pixels.
+Default: not given (sometimes mandatory)
+
+Parameter: height
+Description: A positive number representing the height in pixels.
+Default: not given (sometimes mandatory)
+
+Parameter: bpp
+Description: A positive number representing the depth of a background area.
+ Possible values are 1, 2, 4 and 8 mapping to 2, 4, 8, 16 and 256
+ colors.
+Default: 4 (16 colors)
+
+Parameter: fg
+Description: A hex quadriplet [ TODO is this word correct?! ] introduced by '#'
+ representing a 32-bit foreground color in the order ARGB.
+Default: not given
+Example: #ff000000
+
+Parameter: bg
+Description: A hex quadriplet [ TODO is this word correct?! ] introduced by '#'
+ representing a 32-bit background color in the order ARGB.
+Default: not given
+
+Parameter: font
+Description: A string representing one of VDR's skins, possible values are
+ 'Osd', 'Sml' and 'Fix'.
+Default: Osd
+
+Parameter: path
+Description: A string representing a path- and filename relative to the skin
+ directory. Currently, xpm images and png files (with alphachannel
+ support) can be loaded, but the number of different colors used
+ in the image must not exceed those possible in the corresponding
+ background area.
+Default: not given
+
+Parameter: altpath
+Description: A string representing a path- and filename relative to the skin
+ directory. This is used for for displaying alternate images i.e.
+ for symbols. For more information, see path=...
+Default: not given
+
+Parameter: text
+Description: The string that will be displayed.
+Default: not given
+
+Parameter: align
+Description: A number describing the text alignment. Possible values are '0'
+ for left aligned, '1' for centered and '2' for right aligned.
+Default: 0
+
diff --git a/bitmap.c b/bitmap.c
new file mode 100644
index 0000000..197060c
--- /dev/null
+++ b/bitmap.c
@@ -0,0 +1,63 @@
+/*
+ * $Id: bitmap.c,v 1.1.1.1 2004/05/23 00:08:03 lordjaxom Exp $
+ */
+
+#include <vdr/tools.h>
+#include "bitmap.h"
+#define X_DISPLAY_MISSING
+#include <Imlib2.h>
+
+cText2SkinBitmap::cText2SkinBitmap(void): cBitmap(1, 1, 1) {
+ imlib_set_cache_size(4096 * 1024);
+}
+
+cText2SkinBitmap::cText2SkinBitmap(const char *Filename): cBitmap(1, 1, 1) {
+ imlib_set_cache_size(4096 * 1024);
+ Load(Filename);
+}
+
+cText2SkinBitmap::~cText2SkinBitmap() {
+}
+
+bool cText2SkinBitmap::Load(const char *Filename) {
+ int len = strlen(Filename);
+ if (len > 4) {
+ if (strcmp(Filename + len - 4, ".xpm") == 0)
+ return LoadXpm(Filename);
+#ifdef HAVE_IMLIB
+ else if (strcmp(Filename + len - 4, ".png") == 0)
+ return LoadPng(Filename);
+#endif
+ else
+ esyslog("ERROR: text2skin: unknown file format for %s", Filename);
+ } else
+ esyslog("ERROR: text2skin: filename %s too short to identify format", Filename);
+ return false;
+}
+
+#ifdef HAVE_IMLIB
+bool cText2SkinBitmap::LoadPng(const char *Filename) {
+ Imlib_Image image;
+ image = imlib_load_image(Filename);
+ if (!image)
+ return false;
+ imlib_context_set_image(image);
+ SetSize(imlib_image_get_width(), imlib_image_get_height());
+ SetBpp(4);
+ uint8_t *data = (uint8_t*)imlib_image_get_data_for_reading_only();
+ int pal = 0, pos = 0;
+ for (int y = 0; y < Height(); ++y) {
+ for (int x = 0; x < Width(); ++x) {
+ tColor col = (data[pos + 0] << 24) | (data[pos + 1] << 16) | (data[pos + 2] << 8) | data[pos + 3];
+ int res = Index(col);
+ if (pal > 0 && res == 0)
+ ;//esyslog("ERROR: text2skin: Too many colors used in palette");
+ else
+ SetIndex(x, y, res);
+ pos += 4;
+ }
+ }
+ imlib_free_image();
+ return true;
+}
+#endif
diff --git a/bitmap.h b/bitmap.h
new file mode 100644
index 0000000..09696f5
--- /dev/null
+++ b/bitmap.h
@@ -0,0 +1,22 @@
+/*
+ * $Id: bitmap.h,v 1.1.1.1 2004/05/23 00:08:03 lordjaxom Exp $
+ */
+
+#ifndef VDR_TEXT2SKIN_BITMAP_H
+#define VDR_TEXT2SKIN_BITMAP_H
+
+#include <vdr/osd.h>
+
+class cText2SkinBitmap: public cBitmap {
+public:
+ cText2SkinBitmap(void);
+ cText2SkinBitmap(const char *Filename);
+ virtual ~cText2SkinBitmap();
+
+ bool Load(const char *Filename);
+#ifdef HAVE_IMLIB
+ bool LoadPng(const char *Filename);
+#endif
+};
+
+#endif // VDR_TEXT2SKIN_BITMAP_H
diff --git a/common.c b/common.c
new file mode 100644
index 0000000..b3922aa
--- /dev/null
+++ b/common.c
@@ -0,0 +1,71 @@
+/*
+ * $Id: common.c,v 1.1.1.1 2004/05/23 00:08:03 lordjaxom Exp $
+ */
+
+#include <vdr/plugin.h>
+#include "data.h"
+#include "common.h"
+
+const char *SkinPath(void) {
+ return cPlugin::ConfigDirectory(PLUGIN_NAME_I18N);
+}
+
+const cFont *SkinFont(cText2SkinItem *Item) {
+ const cFont *font;
+ font = cFont::GetFont(fontOsd);
+ if (Item->Font()) {
+ if (strcmp(Item->Font(), "Sml") == 0) font = cFont::GetFont(fontSml);
+ else if (strcmp(Item->Font(), "Fix") == 0) font = cFont::GetFont(fontFix);
+ }
+ return font;
+}
+
+void DrawTextTransparent(cOsd *Osd, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment) {
+ int w = Font->Width(s);
+ int h = Font->Height();
+ int limit = 0;
+ if (Width || Height) {
+ int cw = Width ? Width : w;
+ limit = x + cw;
+ if (Width) {
+ if ((Alignment & taLeft) != 0)
+ ;
+ else if ((Alignment & taRight) != 0) {
+ if (w < Width)
+ x += Width - w;
+ }
+ else { // taCentered
+ if (w < Width)
+ x += (Width - w) / 2;
+ }
+ }
+ if (Height) {
+ if ((Alignment & taTop) != 0)
+ ;
+ else if ((Alignment & taBottom) != 0) {
+ if (h < Height)
+ y += Height - h;
+ }
+ else { // taCentered
+ if (h < Height)
+ y += (Height - h) / 2;
+ }
+ }
+ }
+ while (s && *s) {
+ const cFont::tCharData *CharData = Font->CharData(*s++);
+ if (limit && int(x + CharData->width) > limit)
+ break; // we don't draw partial characters
+ if (int(x + CharData->width) > 0) {
+ for (int row = 0; row < h; row++) {
+ cFont::tPixelData PixelData = CharData->lines[row];
+ for (int col = CharData->width; col-- > 0; ) {
+ if (PixelData & 1)
+ Osd->DrawRectangle(x + col, y + row, x + col, y + row, ColorFg);
+ PixelData >>= 1;
+ }
+ }
+ }
+ x += CharData->width;
+ }
+}
diff --git a/common.h b/common.h
new file mode 100644
index 0000000..e8d01bd
--- /dev/null
+++ b/common.h
@@ -0,0 +1,14 @@
+/*
+ * $Id: common.h,v 1.1.1.1 2004/05/23 00:08:03 lordjaxom Exp $
+ */
+
+#ifndef VDR_TEXT2SKIN_COMMON_H
+#define VDR_TEXT2SKIN_COMMON_H
+
+class cText2SkinItem;
+
+const char *SkinPath(void);
+const cFont *SkinFont(cText2SkinItem *Item);
+void DrawTextTransparent(cOsd *Osd, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment);
+
+#endif // VDR_TEXT2SKIN_COMMON_H
diff --git a/data.c b/data.c
new file mode 100644
index 0000000..8aa6ebc
--- /dev/null
+++ b/data.c
@@ -0,0 +1,196 @@
+/*
+ * $Id: data.c,v 1.1.1.1 2004/05/23 00:08:03 lordjaxom Exp $
+ */
+
+#include "data.h"
+
+eSkinSection cText2SkinItem::mParseSection = sectionUnknown;
+
+cText2SkinItem::cText2SkinItem(void) {
+ mSection = sectionUnknown;
+ mItem = itemUnknown;
+ mX = -1;
+ mY = -1;
+ mWidth = 0;
+ mHeight = 0;
+ mBpp = 4;
+ mFg = NULL;
+ mBg = NULL;
+ mName = NULL;
+ mVersion = NULL;
+ mFont = NULL;
+ mPath = NULL;
+ mAltPath = NULL;
+ mText = NULL;
+ mAlign = taDefault;
+}
+
+cText2SkinItem::~cText2SkinItem() {
+ free(mText);
+ free(mPath);
+ free(mAltPath);
+ free(mFont);
+ free(mVersion);
+ free(mName);
+ delete mBg;
+ delete mFg;
+}
+
+bool cText2SkinItem::Parse(const char *Text) {
+ char *text = strdup(Text);
+ char *ptr = text;
+
+ ptr = text + strlen(text) - 1;
+ for (; ptr >= text && *ptr == ' '; --ptr)
+ *ptr = '\0';
+ ptr = skipspace(text);
+ if (*ptr == '\0' || *ptr == '#') // empty line or comment
+ return true;
+ else if (*ptr == '[' && ptr[strlen(ptr)-1] == ']') { // section
+ ++ptr;
+ ptr[strlen(ptr)-1] = '\0';
+ if (strcmp(ptr, "Channel") == 0) mParseSection = sectionChannel;
+ else if (strcmp(ptr, "Menu") == 0) mParseSection = sectionMenu;
+ else if (strcmp(ptr, "Volume") == 0) mParseSection = sectionVolume;
+ else if (strcmp(ptr, "ReplayMode") == 0) mParseSection = sectionReplayMode;
+ else if (strcmp(ptr, "Replay") == 0) mParseSection = sectionReplay;
+ else if (strcmp(ptr, "Message") == 0) mParseSection = sectionMessage;
+ return true;
+ }
+
+ // check if this is an item
+ char *item;
+ if (ParseVar(ptr, "Item", &item)) {
+ mSection = mParseSection;
+ if (strcmp(item, "Skin") == 0) { // the Skin item
+ if (ParseVar(ptr, "name", &mName) && ParseVar(ptr, "version", &mVersion))
+ mItem = itemSkin;
+ else
+ esyslog("ERROR: text2skin: Skin doesn't contain Item=Skin keyphrase");
+ }
+ else if (strcmp(item, "Background") == 0) mItem = itemBackground;
+ else if (strcmp(item, "Logo") == 0) mItem = itemLogo;
+ else if (strcmp(item, "Text") == 0) mItem = itemText;
+ else if (strcmp(item, "DateTime") == 0) mItem = itemDateTime;
+ else if (strcmp(item, "Date") == 0) mItem = itemDate;
+ else if (strcmp(item, "Time") == 0) mItem = itemTime;
+ else if (strcmp(item, "ChannelNumberName") == 0) mItem = itemChannelNumberName;
+ else if (strcmp(item, "ChannelNumber") == 0) mItem = itemChannelNumber;
+ else if (strcmp(item, "ChannelName") == 0) mItem = itemChannelName;
+ else if (strcmp(item, "Rectangle") == 0) mItem = itemRectangle;
+ else if (strcmp(item, "Ellipse") == 0) mItem = itemEllipse;
+ else if (strcmp(item, "Timebar") == 0) mItem = itemTimebar;
+ else if (strcmp(item, "PresentTime") == 0) mItem = itemPresentTime;
+ else if (strcmp(item, "PresentTitle") == 0) mItem = itemPresentTitle;
+ else if (strcmp(item, "PresentShortText") == 0) mItem = itemPresentShortText;
+ else if (strcmp(item, "FollowingTime") == 0) mItem = itemFollowingTime;
+ else if (strcmp(item, "FollowingTitle") == 0) mItem = itemFollowingTitle;
+ else if (strcmp(item, "FollowingShortText") == 0) mItem = itemFollowingShortText;
+ else if (strcmp(item, "SymbolTeletext") == 0) mItem = itemSymbolTeletext;
+ else if (strcmp(item, "SymbolAudio") == 0) mItem = itemSymbolAudio;
+ else if (strcmp(item, "SymbolDolby") == 0) mItem = itemSymbolDolby;
+ else if (strcmp(item, "SymbolEncrypted") == 0) mItem = itemSymbolEncrypted;
+ else if (strcmp(item, "Volumebar") == 0) mItem = itemVolumebar;
+ else if (strcmp(item, "Mute") == 0) mItem = itemMute;
+ else if (strcmp(item, "Progressbar") == 0) mItem = itemProgressbar;
+ else if (strcmp(item, "MenuArea") == 0) mItem = itemMenuArea;
+ else if (strcmp(item, "MenuItem") == 0) mItem = itemMenuItem;
+ else if (strcmp(item, "MenuCurrent") == 0) mItem = itemMenuCurrent;
+ else
+ esyslog("ERROR: text2skin: %s is not a valid theme item\n", item);
+
+ free(item);
+
+ if (mItem != itemUnknown) {
+ if (mItem != itemSkin)
+ ParseItem(ptr);
+ return true;
+ }
+ } else
+ esyslog("ERROR: text2skin: Missing Item= in Skin");
+
+ // fall through
+ return false;
+}
+
+bool cText2SkinItem::ParseItem(const char *Text) {
+ ParseVar(Text, "x", &mX);
+ ParseVar(Text, "y", &mY);
+ ParseVar(Text, "width", &mWidth);
+ ParseVar(Text, "height", &mHeight);
+ ParseVar(Text, "bpp", &mBpp);
+ ParseVar(Text, "fg", &mFg);
+ ParseVar(Text, "bg", &mBg);
+ ParseVar(Text, "font", &mFont);
+ ParseVar(Text, "path", &mPath);
+ ParseVar(Text, "altpath", &mAltPath);
+ ParseVar(Text, "text", &mText);
+ ParseVar(Text, "align", &mAlign);
+ return true;
+}
+
+bool cText2SkinItem::ParseVar(const char *Text, const char *Name, int *Value) {
+ char *value;
+ if (ParseVar(Text, Name, &value)) {
+ *Value = atoi(value);
+ return true;
+ }
+ return false;
+}
+
+bool cText2SkinItem::ParseVar(const char *Text, const char *Name, char **Value){
+ char *ptr1, *ptr2;
+ char *str;
+ asprintf(&str, "%s=", Name);
+ if ((ptr1 = strstr(Text, str))) {
+ ptr1 += strlen(str);
+ if ((ptr2 = strchr(ptr1, ',')) || (ptr2 = strchr(ptr1, ';'))) {
+ asprintf(Value, "%.*s", ptr2 - ptr1, ptr1);
+ free(str);
+ return true;
+ }
+ }
+ free(str);
+ return false;
+}
+
+bool cText2SkinItem::ParseVar(const char *Text, const char *Name, tColor **Value) {
+ char *value;
+ if (ParseVar(Text, Name, &value) && *value == '#') {
+ *Value = new tColor(strtoul(value + 1, NULL, 16));
+ return true;
+ }
+ return false;
+}
+
+bool cText2SkinItem::ParseVar(const char *Text, const char *Name, eTextAlignment *Value) {
+ char *value;
+ if (ParseVar(Text, Name, &value)) {
+ int v = atoi(value);
+ free(value);
+ if (v == 0)
+ *Value = (eTextAlignment)(taTop|taLeft);
+ else if (v == 1)
+ *Value = (eTextAlignment)(taTop|taCenter);
+ else if (v == 2)
+ *Value = (eTextAlignment)(taTop|taRight);
+ return true;
+ }
+ return false;
+}
+
+cText2SkinData::cText2SkinData(const char *Skin) {
+ mSkin = strdup(Skin);
+}
+
+cText2SkinData::~cText2SkinData() {
+ free(mSkin);
+}
+
+cText2SkinItem *cText2SkinData::Get(eSkinItem Item) {
+ for (cText2SkinItem *it = First(); it; it = Next(it)) {
+ if (it->Item() == Item)
+ return it;
+ }
+ return NULL;
+}
diff --git a/data.h b/data.h
new file mode 100644
index 0000000..69327bc
--- /dev/null
+++ b/data.h
@@ -0,0 +1,125 @@
+/*
+ * $Id: data.h,v 1.1.1.1 2004/05/23 00:08:03 lordjaxom Exp $
+ */
+
+#ifndef VDR_TEXT2SKIN_DATA_H
+#define VDR_TEXT2SKIN_DATA_H
+
+#include <vdr/tools.h>
+#include <vdr/osd.h>
+#include <vdr/config.h>
+
+// sections and items known by skin files
+
+enum eSkinSection {
+ sectionUnknown,
+ sectionChannel,
+ sectionVolume,
+ sectionReplayMode,
+ sectionReplay,
+ sectionMessage,
+ sectionMenu,
+};
+
+enum eSkinItem {
+ itemUnknown,
+ itemSkin, // item identifying the Skin itself
+ itemBackground,
+ itemLogo,
+ itemText,
+ itemDateTime,
+ itemDate,
+ itemTime,
+ itemChannelNumberName,
+ itemChannelNumber,
+ itemChannelName,
+ itemRectangle,
+ itemEllipse,
+ itemTimebar,
+ itemPresentTime,
+ itemPresentTitle,
+ itemPresentShortText,
+ itemFollowingTime,
+ itemFollowingTitle,
+ itemFollowingShortText,
+ itemSymbolTeletext,
+ itemSymbolAudio,
+ itemSymbolDolby,
+ itemSymbolEncrypted,
+ itemVolumebar,
+ itemMute,
+ itemProgressbar,
+ itemReplayTitle,
+ itemMenuArea,
+ itemMenuItem,
+ itemMenuCurrent
+};
+
+class cText2SkinItem: public cListObject {
+ friend class cText2SkinRender;
+
+private:
+ static eSkinSection mParseSection;
+
+ eSkinSection mSection;
+ eSkinItem mItem;
+ int mX, mY;
+ int mWidth, mHeight;
+ int mBpp;
+ tColor *mFg;
+ tColor *mBg;
+ char *mName;
+ char *mVersion;
+ char *mFont;
+ char *mPath;
+ char *mAltPath;
+ char *mText;
+ eTextAlignment mAlign;
+
+protected:
+ bool ParseItem(const char *Text);
+ bool ParseVar(const char *Text, const char *Name, int *Value);
+ bool ParseVar(const char *Text, const char *Name, char **Value);
+ bool ParseVar(const char *Text, const char *Name, tColor **Value);
+ bool ParseVar(const char *Text, const char *Name, eTextAlignment *Value);
+
+public:
+ cText2SkinItem(void);
+ ~cText2SkinItem();
+
+ bool Parse(const char *Text);
+
+ eSkinSection Section(void) const { return mSection; }
+ eSkinItem Item(void) const { return mItem; }
+ int X(void) const { return mX; }
+ int Y(void) const { return mY; }
+ int Width(void) const { return mWidth; }
+ int Height(void) const { return mHeight; }
+ int Bpp(void) const { return mBpp; }
+ bool HasFg(void) const { return mFg != NULL; }
+ tColor Fg(void) const { return mFg ? *mFg : 0xFFFFFFFF; }
+ bool HasBg(void) const { return mBg != NULL; }
+ tColor Bg(void) const { return mBg ? *mBg : 0xFF000000; }
+ const char *Name(void) const { return mName; }
+ const char *Version(void) const { return mVersion; }
+ const char *Font(void) const { return mFont; }
+ const char *Path(void) const { return mPath; }
+ const char *AltPath(void) const { return mAltPath; }
+ const char *Text(void) const { return mText; }
+ eTextAlignment Align(void) const { return mAlign; }
+};
+
+class cText2SkinData: public cConfig<cText2SkinItem> {
+private:
+ char *mSkin;
+
+public:
+ cText2SkinData(const char *Skin);
+ ~cText2SkinData();
+
+ cText2SkinItem *Get(eSkinItem Item);
+
+ const char *Skin(void) const { return mSkin; }
+};
+
+#endif // VDR_TEXT2SKIN_DATA_H
diff --git a/display.c b/display.c
new file mode 100644
index 0000000..395205d
--- /dev/null
+++ b/display.c
@@ -0,0 +1,236 @@
+/*
+ * $Id: display.c,v 1.1.1.1 2004/05/23 00:08:03 lordjaxom Exp $
+ */
+
+#include "display.h"
+#include "data.h"
+#include "render.h"
+
+// --- cText2SkinDisplayChannel -----------------------------------------------
+
+cText2SkinDisplayChannel::cText2SkinDisplayChannel(cText2SkinData *Data, bool WithInfo) {
+ printf("cText2SkinDisplayChannel\n");
+ mData = Data;
+ mWithInfo = WithInfo;
+ mRender = new cText2SkinRender(mData, sectionChannel);
+ mDirty = false;
+}
+
+cText2SkinDisplayChannel::~cText2SkinDisplayChannel() {
+ delete mRender;
+}
+
+void cText2SkinDisplayChannel::SetChannel(const cChannel *Channel, int Number) {
+ printf("SetChannel\n");
+ if (mRender->mChannel != Channel || mRender->mNumber != Number) {
+ mRender->mChannel = Channel;
+ mRender->mNumber = Number;
+ mDirty = true;
+ }
+}
+
+void cText2SkinDisplayChannel::SetEvents(const cEvent *Present, const cEvent *Following) {
+ if (mRender->mPresent != Present || mRender->mFollowing != Following) {
+ mRender->mPresent = Present;
+ mRender->mFollowing = Following;
+ mDirty = true;
+ }
+}
+
+void cText2SkinDisplayChannel::Flush(void) {
+ if (mDirty) {
+ printf("real flush\n");
+ mRender->Flush();
+ mDirty = false;
+ }
+}
+
+// --- cText2SkinDisplayVolume ------------------------------------------------
+
+cText2SkinDisplayVolume::cText2SkinDisplayVolume(cText2SkinData *Data) {
+ printf("cText2SkinDisplayVolume\n");
+ mData = Data;
+ mRender = new cText2SkinRender(mData, sectionVolume);
+ mDirty = false;
+}
+
+cText2SkinDisplayVolume::~cText2SkinDisplayVolume() {
+ delete mRender;
+}
+
+void cText2SkinDisplayVolume::SetVolume(int Current, int Total, bool Mute) {
+ if (mRender->mVolumeCurrent != Current || mRender->mVolumeTotal != Total || mRender->mVolumeMute != Mute) {
+ mRender->mVolumeCurrent = Current;
+ mRender->mVolumeTotal = Total;
+ mRender->mVolumeMute = Mute;
+ mDirty = true;
+ }
+}
+
+void cText2SkinDisplayVolume::Flush(void) {
+ if (mDirty) {
+ printf("real flush\n");
+ mRender->Flush();
+ mDirty = false;
+ }
+}
+
+// --- cText2SkinDisplayReplay ------------------------------------------------
+
+cText2SkinDisplayReplay::cText2SkinDisplayReplay(cText2SkinData *Data, bool ModeOnly) {
+ printf("cText2SkinDisplayVolume\n");
+ mData = Data;
+ mRender = new cText2SkinRender(mData, ModeOnly ? sectionReplayMode : sectionReplay);
+ mDirty = false;
+}
+
+cText2SkinDisplayReplay::~cText2SkinDisplayReplay() {
+ delete mRender;
+}
+
+void cText2SkinDisplayReplay::SetTitle(const char *Title) {
+ if (mRender->mReplayTitle != Title) {
+ mRender->mReplayTitle = Title;
+ mDirty = true;
+ }
+}
+
+void cText2SkinDisplayReplay::SetMode(bool Play, bool Forward, int Speed) {
+ if (mRender->mReplayPlay != Play || mRender->mReplayPlay != Forward || mRender->mReplaySpeed != Speed) {
+ mRender->mReplayPlay = Play;
+ mRender->mReplayForward = Forward;
+ mRender->mReplaySpeed = Speed;
+ mDirty = true;
+ }
+}
+
+void cText2SkinDisplayReplay::SetProgress(int Current, int Total) {
+ if (mRender->mReplayCurrent != Current || mRender->mReplayTotal != Total) {
+ mRender->mReplayCurrent = Current;
+ mRender->mReplayTotal = Total;
+ mDirty = true;
+ }
+}
+
+void cText2SkinDisplayReplay::SetCurrent(const char *Current) {
+}
+
+void cText2SkinDisplayReplay::SetTotal(const char *Total) {
+}
+
+void cText2SkinDisplayReplay::SetJump(const char *Jump) {
+ if (mRender->mReplayJump != Jump) {
+ mRender->mReplayJump = NULL;
+ mDirty = true;
+ }
+}
+
+void cText2SkinDisplayReplay::Flush(void) {
+ if (mDirty) {
+ printf("real flush\n");
+ mRender->Flush();
+ mDirty = false;
+ }
+}
+
+// --- cText2SkinDisplayMessage -----------------------------------------------
+
+cText2SkinDisplayMessage::cText2SkinDisplayMessage(cText2SkinData *Data) {
+ printf("cText2SkinDisplayMessage\n");
+ mData = Data;
+ mRender = new cText2SkinRender(mData, sectionMessage);
+ mDirty = false;
+}
+
+cText2SkinDisplayMessage::~cText2SkinDisplayMessage() {
+ delete mRender;
+}
+
+void cText2SkinDisplayMessage::SetMessage(eMessageType Type, const char *Text) {
+ if (mRender->mMessageType != Type || mRender->mMessageText != Text) {
+ mRender->mMessageType = Type;
+ mRender->mMessageText = Text;
+ mDirty = true;
+ }
+}
+
+void cText2SkinDisplayMessage::Flush(void) {
+ if (mDirty) {
+ printf("real flush\n");
+ mRender->Flush();
+ mDirty = false;
+ }
+}
+
+// --- cText2SkinDisplayMenu --------------------------------------------------
+
+cText2SkinDisplayMenu::cText2SkinDisplayMenu(cText2SkinData *Data) {
+ printf("cText2SkinDisplayMenu\n");
+ mData = Data;
+ mRender = new cText2SkinRender(mData, sectionMenu);
+ mDirty = false;
+ mMaxItems = 0;
+
+ cText2SkinItem *area = mData->Get(itemMenuArea);
+ cText2SkinItem *item = mData->Get(itemMenuItem);
+ if (area && item)
+ mMaxItems = area->Height() / item->Height();
+ else
+ esyslog("ERROR: text2skin: Skin is missing the items MenuArea and/or MenuItem");
+}
+
+cText2SkinDisplayMenu::~cText2SkinDisplayMenu() {
+ delete mRender;
+}
+
+void cText2SkinDisplayMenu::Clear(void) {
+ mRender->mItems.clear();
+ mRender->mCurrent = -1;
+ mDirty = true;
+}
+
+void cText2SkinDisplayMenu::SetTitle(const char *Title) {
+ if (mRender->mTitle != Title) {
+ mRender->mTitle = Title;
+ mDirty = true;
+ }
+}
+
+void cText2SkinDisplayMenu::SetButtons(const char *Red, const char *Green, const char *Yellow, const char *Blue) {
+}
+
+void cText2SkinDisplayMenu::SetMessage(eMessageType Type, const char *Text) {
+}
+
+void cText2SkinDisplayMenu::SetItem(const char *Text, int Index, bool Current, bool Selectable) {
+ cText2SkinRender::MenuItem item = { Text, Selectable };
+ if ((int)mRender->mItems.size() <= Index) {
+ mRender->mItems.push_back(item);
+ mDirty = true;
+ } else if (mRender->mItems[Index] != item) {
+ mRender->mItems[Index] = item;
+ mDirty = true;
+ }
+ if (Current && mRender->mCurrent != Index) {
+ mRender->mCurrent = Index;
+ mDirty = true;
+ }
+}
+
+void cText2SkinDisplayMenu::SetEvent(const cEvent *Event) {
+}
+
+void cText2SkinDisplayMenu::SetRecording(const cRecording *Recording) {
+}
+
+void cText2SkinDisplayMenu::SetText(const char *Text, bool FixedFont) {
+}
+
+void cText2SkinDisplayMenu::Flush(void) {
+ if (mDirty) {
+ printf("real flush\n");
+ mRender->Flush();
+ mDirty = false;
+ }
+}
+
diff --git a/display.h b/display.h
new file mode 100644
index 0000000..7637038
--- /dev/null
+++ b/display.h
@@ -0,0 +1,95 @@
+/*
+ * $Id: display.h,v 1.1.1.1 2004/05/23 00:08:03 lordjaxom Exp $
+ */
+
+#ifndef VDR_TEXT2SKIN_SKIN_H
+#define VDR_TEXT2SKIN_SKIN_H
+
+#include <vdr/skins.h>
+
+class cText2SkinData;
+class cText2SkinRender;
+
+class cText2SkinDisplayChannel: public cSkinDisplayChannel {
+private:
+ cText2SkinData *mData;
+ bool mWithInfo;
+ cText2SkinRender *mRender;
+ bool mDirty;
+
+public:
+ cText2SkinDisplayChannel(cText2SkinData *Data, bool WithInfo);
+ virtual ~cText2SkinDisplayChannel();
+
+ virtual void SetChannel(const cChannel *Channel, int Number);
+ virtual void SetEvents(const cEvent *Present, const cEvent *Following);
+ virtual void Flush(void);
+};
+
+class cText2SkinDisplayVolume: public cSkinDisplayVolume {
+private:
+ cText2SkinData *mData;
+ cText2SkinRender *mRender;
+ bool mDirty;
+
+public:
+ cText2SkinDisplayVolume(cText2SkinData *Data);
+ virtual ~cText2SkinDisplayVolume();
+ virtual void SetVolume(int Current, int Total, bool Mute);
+ virtual void Flush(void);
+};
+
+class cText2SkinDisplayReplay: public cSkinDisplayReplay {
+private:
+ cText2SkinData *mData;
+ cText2SkinRender *mRender;
+ bool mDirty;
+public:
+ cText2SkinDisplayReplay(cText2SkinData *Data, bool ModeOnly);
+ virtual ~cText2SkinDisplayReplay();
+ virtual void SetTitle(const char *Title);
+ virtual void SetMode(bool Play, bool Forward, int Speed);
+ virtual void SetProgress(int Current, int Total);
+ virtual void SetCurrent(const char *Current);
+ virtual void SetTotal(const char *Total);
+ virtual void SetJump(const char *Jump);
+ virtual void Flush(void);
+};
+
+class cText2SkinDisplayMessage: public cSkinDisplayMessage {
+private:
+ cText2SkinData *mData;
+ cText2SkinRender *mRender;
+ bool mDirty;
+
+public:
+ cText2SkinDisplayMessage(cText2SkinData *Data);
+ virtual ~cText2SkinDisplayMessage();
+ virtual void SetMessage(eMessageType Type, const char *Text);
+ virtual void Flush(void);
+};
+
+class cText2SkinDisplayMenu: public cSkinDisplayMenu {
+private:
+ cText2SkinData *mData;
+ cText2SkinRender *mRender;
+ bool mDirty;
+ int mMaxItems;
+
+public:
+ cText2SkinDisplayMenu(cText2SkinData *Data);
+ virtual ~cText2SkinDisplayMenu();
+
+ virtual int MaxItems(void) { return mMaxItems; }
+ virtual void Clear(void);
+ virtual void SetTitle(const char *Title);
+ virtual void SetButtons(const char *Red, const char *Green, const char *Yellow, const char *Blue);
+ virtual void SetMessage(eMessageType Type, const char *Text);
+ virtual void SetItem(const char *Text, int Index, bool Current, bool Selectable);
+ virtual void SetEvent(const cEvent *Event);
+ virtual void SetRecording(const cRecording *Recording);
+ virtual void SetText(const char *Text, bool FixedFont);
+ virtual void Flush(void);
+};
+
+#endif // VDR_TEXT2SKIN_SKIN_H
diff --git a/loader.c b/loader.c
new file mode 100644
index 0000000..c5d71af
--- /dev/null
+++ b/loader.c
@@ -0,0 +1,79 @@
+/*
+ * $Id: loader.c,v 1.1.1.1 2004/05/23 00:08:03 lordjaxom Exp $
+ */
+
+#include <vdr/plugin.h>
+#include "loader.h"
+#include "data.h"
+#include "display.h"
+#include "common.h"
+#include <sys/types.h>
+#include <dirent.h>
+
+static cTheme Theme;
+
+void cText2SkinLoader::Start(void) {
+ DIR *d = opendir(SkinPath());
+ if (d) {
+ struct dirent *ent;
+ while ((ent = readdir(d)) != NULL) {
+ char *path;
+ struct stat buf;
+ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+ continue;
+ asprintf(&path, "%s/%s", SkinPath(), ent->d_name);
+ if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode))
+ Load(ent->d_name);
+ free(path);
+ }
+ closedir(d);
+ }
+}
+
+void cText2SkinLoader::Load(const char *Skin) {
+ char *skinfile;
+ struct stat buf;
+ asprintf(&skinfile, "%s/%s/%s.skin", SkinPath(), Skin, Skin);
+ if (stat(skinfile, &buf) == 0) {
+ cText2SkinData *data = new cText2SkinData(Skin);
+ if (data->Load(skinfile)) {
+ cText2SkinItem *skin = data->Get(itemSkin);
+ if (skin) {
+ new cText2SkinLoader(data, Skin, skin->Name());
+ return;
+ } else
+ esyslog("ERROR: Item=Skin is missing in Skin\n");
+ }
+ delete data;
+ } else
+ esyslog("ERROR: text2skin: %s/%s is not a valid skin directory\n", SkinPath(), Skin);
+}
+
+cText2SkinLoader::cText2SkinLoader(cText2SkinData *Data, const char *Skin, const char *Description): cSkin(Skin, &::Theme) {
+ mData = Data;
+ mDescription = Description;
+}
+
+cText2SkinLoader::~cText2SkinLoader() {
+ delete mData;
+ // mDescription is part of mData
+}
+
+cSkinDisplayChannel *cText2SkinLoader::DisplayChannel(bool WithInfo) {
+ return new cText2SkinDisplayChannel(mData, WithInfo);
+}
+
+cSkinDisplayMenu *cText2SkinLoader::DisplayMenu(void) {
+ return new cText2SkinDisplayMenu(mData);
+}
+
+cSkinDisplayVolume *cText2SkinLoader::DisplayVolume(void) {
+ return new cText2SkinDisplayVolume(mData);
+}
+
+cSkinDisplayReplay *cText2SkinLoader::DisplayReplay(bool ModeOnly) {
+ return new cText2SkinDisplayReplay(mData, ModeOnly);
+}
+cSkinDisplayMessage *cText2SkinLoader::DisplayMessage(void) {
+ return new cText2SkinDisplayMessage(mData);
+}
diff --git a/loader.h b/loader.h
new file mode 100644
index 0000000..194f2fa
--- /dev/null
+++ b/loader.h
@@ -0,0 +1,32 @@
+/*
+ * $Id: loader.h,v 1.1.1.1 2004/05/23 00:08:03 lordjaxom Exp $
+ */
+
+#ifndef VDR_TEXT2SKIN_LOADER_H
+#define VDR_TEXT2SKIN_LOADER_H
+
+#include <vdr/skins.h>
+
+class cText2SkinData;
+
+class cText2SkinLoader: public cSkin {
+private:
+ cText2SkinData *mData;
+ const char *mDescription;
+
+public:
+ static void Start(void);
+ static void Load(const char *Skin);
+
+ cText2SkinLoader(cText2SkinData *Data, const char *Skin, const char *Description);
+ ~cText2SkinLoader();
+
+ virtual const char *Description(void) { return mDescription; };
+ virtual cSkinDisplayChannel *DisplayChannel(bool WithInfo);
+ virtual cSkinDisplayMenu *DisplayMenu(void);
+ virtual cSkinDisplayReplay *DisplayReplay(bool ModeOnly);
+ virtual cSkinDisplayVolume *DisplayVolume(void);
+ virtual cSkinDisplayMessage *DisplayMessage(void);
+};
+
+#endif // VDR_TEXT2SKIN_LOADER_H
diff --git a/render.c b/render.c
new file mode 100644
index 0000000..0ae8c5d
--- /dev/null
+++ b/render.c
@@ -0,0 +1,370 @@
+/*
+ * $Id: render.c,v 1.1.1.1 2004/05/23 00:08:03 lordjaxom Exp $
+ */
+
+#include <vdr/channels.h>
+#include <vdr/epg.h>
+#include "render.h"
+#include "data.h"
+#include "bitmap.h"
+#include "common.h"
+
+cText2SkinRender::cText2SkinRender(cText2SkinData *Data, eSkinSection Section) {
+ tArea areas[MAXOSDAREAS];
+ int numAreas = 0;
+
+ mData = Data;
+ mSection = Section;
+ mOsd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop);
+ mChannel = NULL;
+ mNumber = 0;
+ mVolumeCurrent = 0;
+ mVolumeTotal = 0;
+ mVolumeMute = false;
+ mReplayTitle = NULL;
+ mReplayPlay = false;
+ mReplayForward = false;
+ mReplaySpeed = 0;
+ mReplayCurrent = 0;
+ mReplayTotal = 0;
+ mReplayJump = NULL;
+ mMessageType = (eMessageType)-1;
+ mMessageText = NULL;
+ mPresent = NULL;
+ mFollowing = NULL;
+ mTitle = NULL;
+ mCurrent = 0;
+
+ cText2SkinItem *item;
+ for (item = Data->First(); item; item = Data->Next(item)) {
+ if (item->Section() == Section && item->Item() == itemBackground) {
+ if (numAreas < MAXOSDAREAS) {
+ printf("area item: %d:%d:%d:%d\n", item->X(), item->Y(), item->X() + item->Width() - 1, item->Y() + item->Height() - 1, item->Bpp());
+ areas[numAreas].x1 = item->X();
+ areas[numAreas].y1 = item->Y();
+ areas[numAreas].x2 = item->X() + item->Width() - 1;
+ areas[numAreas].y2 = item->Y() + item->Height() - 1;
+ areas[numAreas].bpp = item->Bpp();
+ ++numAreas;
+ } else
+ esyslog("ERROR: text2skin: too many background areas\n");
+ }
+ }
+
+ eOsdError res;
+ if ((res = mOsd->CanHandleAreas(areas, numAreas)) == oeOk)
+ mOsd->SetAreas(areas, numAreas);
+ else {
+ const char *emsg = NULL;
+ switch (res) {
+ case oeTooManyAreas:
+ emsg = "Too many OSD areas"; break;
+ case oeTooManyColors:
+ emsg = "Too many Colors"; break;
+ case oeBppNotSupported:
+ emsg = "Depth not supported"; break;
+ case oeAreasOverlap:
+ emsg = "Areas are overlapping"; break;
+ case oeWrongAlignment:
+ emsg = "Areas not correctly aligned"; break;
+ case oeOutOfMemory:
+ emsg = "OSD memory overflow"; break;
+ case oeUnknown:
+ emsg = "Unknown OSD error"; break;
+ default:
+ break;
+ }
+ esyslog("ERROR: text2skin: OSD provider can't handle skin: %s\n", emsg);
+ }
+}
+
+cText2SkinRender::~cText2SkinRender() {
+ delete mOsd;
+}
+
+void cText2SkinRender::Flush(void) {
+ cText2SkinItem *item;
+ for (item = mData->First(); item; item = mData->Next(item)) {
+ if (item->Section() == mSection) {
+ switch (item->Item()) {
+ case itemBackground:
+ DisplayBackground(item); break;
+ case itemLogo:
+ DisplayLogo(item); break;
+ case itemText:
+ DisplayText(item); break;
+ case itemDateTime:
+ DisplayDateTime(item); break;
+ case itemDate:
+ DisplayDate(item); break;
+ case itemTime:
+ DisplayTime(item); break;
+ case itemChannelNumberName:
+ DisplayChannelNumberName(item); break;
+ case itemChannelNumber:
+ DisplayChannelNumber(item); break;
+ case itemChannelName:
+ DisplayChannelName(item); break;
+ case itemRectangle:
+ DisplayRectangle(item); break;
+ case itemEllipse:
+ DisplayEllipse(item); break;
+ case itemTimebar:
+ DisplayTimebar(item); break;
+ case itemPresentTime:
+ DisplayPresentTime(item); break;
+ case itemPresentTitle:
+ DisplayPresentTitle(item); break;
+ case itemPresentShortText:
+ DisplayPresentShortText(item); break;
+ case itemFollowingTime:
+ DisplayFollowingTime(item); break;
+ case itemFollowingTitle:
+ DisplayFollowingTitle(item); break;
+ case itemFollowingShortText:
+ DisplayFollowingShortText(item); break;
+ case itemSymbolTeletext:
+ case itemSymbolAudio:
+ case itemSymbolDolby:
+ case itemSymbolEncrypted:
+ DisplaySymbol(item); break;
+ case itemVolumebar:
+ DisplayVolumebar(item); break;
+ case itemMute:
+ DisplayMute(item); break;
+ case itemProgressbar:
+ DisplayProgressbar(item); break;
+ case itemReplayTitle:
+ DisplayReplayTitle(item); break;
+ case itemMenuItem:
+ DisplayMenuItems(item); break;
+ default:
+ break;
+ }
+ }
+ }
+ printf("osd flush\n");
+ mOsd->Flush();
+}
+
+void cText2SkinRender::DisplayBackground(cText2SkinItem *Item) {
+ printf("DisplayBackground\n");
+ if (Item->Path()) {
+ char *p;
+ asprintf(&p, "%s/%s/%s", SkinPath(), mData->Skin(), Item->Path());
+ cText2SkinBitmap bm(p);
+ free(p);
+ if (Item->HasBg()) bm.SetColor(0, Item->Bg());
+ if (Item->HasFg()) bm.SetColor(1, Item->Fg());
+ mOsd->DrawBitmap(Item->X(), Item->Y(), bm);
+ } else {
+ printf("drawing plain background\n");
+ }
+}
+
+void cText2SkinRender::DisplayLogo(cText2SkinItem *Item) {
+}
+
+void cText2SkinRender::DisplayText(cText2SkinItem *Item) {
+ printf("DisplayText\n");
+ DrawTextTransparent(mOsd, Item->X(), Item->Y(), Item->Text(), Item->Fg(), Item->Bg(), SkinFont(Item), Item->Width(), Item->Height(), Item->Align());
+}
+
+void cText2SkinRender::DisplayDateTime(cText2SkinItem *Item) {
+ const char *text = DayDateTime(time(NULL));
+ DrawTextTransparent(mOsd, Item->X(), Item->Y(), text, Item->Fg(), Item->Bg(), SkinFont(Item), Item->Width(), Item->Height(), Item->Align());
+}
+
+void cText2SkinRender::DisplayDate(cText2SkinItem *Item) {
+ char *text = strdup(DayDateTime(time(NULL)));
+ text[10] = '\0';
+ DrawTextTransparent(mOsd, Item->X(), Item->Y(), text + 5, Item->Fg(), Item->Bg(), SkinFont(Item), Item->Width(), Item->Height(), Item->Align());
+ free(text);
+}
+
+void cText2SkinRender::DisplayTime(cText2SkinItem *Item) {
+ char *text = strdup(DayDateTime(time(NULL)));
+ text[18] = '\0';
+ DrawTextTransparent(mOsd, Item->X(), Item->Y(), text + 13, Item->Fg(), Item->Bg(), SkinFont(Item), Item->Width(), Item->Height(), Item->Align());
+}
+
+void cText2SkinRender::DisplayChannelNumberName(cText2SkinItem *Item) {
+ DrawTextTransparent(mOsd, Item->X(), Item->Y(), ChannelString(mChannel, mNumber), Item->Fg(), Item->Bg(), SkinFont(Item), Item->Width(), Item->Height(), Item->Align());
+}
+
+void cText2SkinRender::DisplayChannelNumber(cText2SkinItem *Item) {
+ char *text = strdup(ChannelString(mChannel, mNumber));
+ char *ptr = text;
+ while (*ptr && *ptr != ' ') ++ptr;
+ *ptr = '\0';
+ DrawTextTransparent(mOsd, Item->X(), Item->Y(), text, Item->Fg(), Item->Bg(), SkinFont(Item), Item->Width(), Item->Height(), Item->Align());
+ free(text);
+}
+
+void cText2SkinRender::DisplayChannelName(cText2SkinItem *Item) {
+ const char *text = ChannelString(mChannel, mNumber);
+ while (*text && *text != ' ') ++text;
+ if (strlen(text) > 1)
+ DrawTextTransparent(mOsd, Item->X(), Item->Y(), text + 1, Item->Fg(), Item->Bg(), SkinFont(Item), Item->Width(), Item->Height(), Item->Align());
+}
+
+void cText2SkinRender::DisplayRectangle(cText2SkinItem *Item) {
+ mOsd->DrawRectangle(Item->X(), Item->Y(), Item->X() + Item->Width() - 1, Item->Y() + Item->Height() - 1, Item->Fg());
+
+}
+
+void cText2SkinRender::DisplayEllipse(cText2SkinItem *Item) {
+ mOsd->DrawEllipse(Item->X(), Item->Y(), Item->X() + Item->Width() - 1, Item->Y() + Item->Height() - 1, Item->Fg());
+}
+
+void cText2SkinRender::DisplayTimebar(cText2SkinItem *Item) {
+ time_t now = time(NULL);
+ if (mPresent && now > mPresent->StartTime()) {
+ int total = mPresent->Duration();
+ int current = total - (now - mPresent->StartTime());
+ if (Item->Width() > Item->Height()) {
+ mOsd->DrawRectangle(Item->X(), Item->Y(), Item->X() + Item->Width() - 1, Item->Y() + Item->Height() - 1, Item->Bg());
+ mOsd->DrawRectangle(Item->X() + 2, Item->Y() + 2, Item->X() + (Item->Width() * current / total) - 3, Item->Y() + Item->Height() - 3, Item->Fg());
+ } else {
+ mOsd->DrawRectangle(Item->X(), Item->Y(), Item->X() + Item->Width() - 3, Item->Y() + Item->Height() - 3, Item->Bg());
+ mOsd->DrawRectangle(Item->X() + 2, Item->Y() + 2, Item->X() + Item->Width() - 3, Item->Y() + (Item->Height() * current / total) - 3, Item->Fg());
+ }
+ }
+}
+
+void cText2SkinRender::DisplayPresentTime(cText2SkinItem *Item) {
+ if (mPresent) {
+ const char *text = DayDateTime(mPresent->StartTime());
+ DrawTextTransparent(mOsd, Item->X(), Item->Y(), text + 10, Item->Fg(), Item->Bg(), SkinFont(Item), Item->Width(), Item->Height(), Item->Align());
+ }
+}
+
+void cText2SkinRender::DisplayPresentTitle(cText2SkinItem *Item) {
+ if (mPresent && mPresent->Title())
+ DrawTextTransparent(mOsd, Item->X(), Item->Y(), mPresent->Title(), Item->Fg(), Item->Bg(), SkinFont(Item), Item->Width(), Item->Height(), Item->Align());
+}
+
+void cText2SkinRender::DisplayPresentShortText(cText2SkinItem *Item) {
+ if (mPresent && mPresent->ShortText())
+ DrawTextTransparent(mOsd, Item->X(), Item->Y(), mPresent->ShortText(), Item->Fg(), Item->Bg(), SkinFont(Item), Item->Width(), Item->Height(), Item->Align());
+}
+
+void cText2SkinRender::DisplayFollowingTime(cText2SkinItem *Item) {
+ if (mFollowing) {
+ const char *text = DayDateTime(mFollowing->StartTime());
+ DrawTextTransparent(mOsd, Item->X(), Item->Y(), text + 10, Item->Fg(), Item->Bg(), SkinFont(Item), Item->Width(), Item->Height(), Item->Align());
+ }
+}
+
+void cText2SkinRender::DisplayFollowingTitle(cText2SkinItem *Item) {
+ if (mFollowing && mFollowing->Title())
+ DrawTextTransparent(mOsd, Item->X(), Item->Y(), mFollowing->Title(), Item->Fg(), Item->Bg(), SkinFont(Item), Item->Width(), Item->Height(), Item->Align());
+}
+
+void cText2SkinRender::DisplayFollowingShortText(cText2SkinItem *Item) {
+ if (mFollowing && mFollowing->ShortText())
+ DrawTextTransparent(mOsd, Item->X(), Item->Y(), mFollowing->ShortText(), Item->Fg(), Item->Bg(), SkinFont(Item), Item->Width(), Item->Height(), Item->Align());
+}
+
+void cText2SkinRender::DisplaySymbol(cText2SkinItem *Item) {
+ const char *image = NULL;
+ if (mSection == sectionChannel && mChannel) {
+ switch (Item->Item()) {
+ case itemSymbolTeletext:
+ image = mChannel->Tpid() ? Item->Path() : Item->AltPath(); break;
+ case itemSymbolAudio:
+ image = mChannel->Apid2() ? Item->Path() : Item->AltPath(); break;
+ case itemSymbolDolby:
+ image = mChannel->Dpid1() ? Item->Path() : Item->AltPath(); break;
+ case itemSymbolEncrypted:
+ image = mChannel->Ca() ? Item->Path() : Item->AltPath(); break;
+ default:
+ break;
+ }
+ }
+ if (image) {
+ char *p;
+ asprintf(&p, "%s/%s/%s", SkinPath(), mData->Skin(), image);
+ printf("trying %s\n", p);
+ cText2SkinBitmap bm(p);
+ free(p);
+ if (Item->HasBg()) bm.SetColor(0, Item->Bg());
+ if (Item->HasFg()) bm.SetColor(1, Item->Fg());
+ mOsd->DrawBitmap(Item->X(), Item->Y(), bm);
+ }
+}
+
+void cText2SkinRender::DisplayVolumebar(cText2SkinItem *Item) {
+ if (mVolumeTotal && mVolumeCurrent <= mVolumeTotal) {
+ int total = mVolumeTotal;
+ int current = mVolumeCurrent;
+ if (Item->Width() > Item->Height()) {
+ mOsd->DrawRectangle(Item->X(), Item->Y(), Item->X() + Item->Width() - 1, Item->Y() + Item->Height() - 1, Item->Bg());
+ mOsd->DrawRectangle(Item->X() + 2, Item->Y() + 2, Item->X() + (Item->Width() * current / total) - 3, Item->Y() + Item->Height() - 3, Item->Fg());
+ } else {
+ mOsd->DrawRectangle(Item->X(), Item->Y(), Item->X() + Item->Width() - 3, Item->Y() + Item->Height() - 3, Item->Bg());
+ mOsd->DrawRectangle(Item->X() + 2, Item->Y() + 2, Item->X() + Item->Width() - 3, Item->Y() + (Item->Height() * current / total) - 3, Item->Fg());
+ }
+ }
+}
+
+void cText2SkinRender::DisplayMute(cText2SkinItem *Item) {
+ if (mVolumeMute) {
+ if (Item->Path()) {
+ char *p;
+ asprintf(&p, "%s/%s/%s", SkinPath(), mData->Skin(), Item->Path());
+ cText2SkinBitmap bm(p);
+ free(p);
+ if (Item->HasBg()) bm.SetColor(0, Item->Bg());
+ if (Item->HasFg()) bm.SetColor(1, Item->Fg());
+ mOsd->DrawBitmap(Item->X(), Item->Y(), bm);
+ }
+
+ if (Item->Text()) {
+ DrawTextTransparent(mOsd, Item->X(), Item->Y(), Item->Text(), Item->Fg(), Item->Bg(), SkinFont(Item), Item->Width(), Item->Height(), Item->Align());
+ }
+ }
+}
+
+void cText2SkinRender::DisplayProgressbar(cText2SkinItem *Item) {
+ if (mReplayTotal && mReplayCurrent <= mReplayTotal) {
+ int total = mReplayTotal;
+ int current = mReplayCurrent;
+ if (Item->Width() > Item->Height()) {
+ mOsd->DrawRectangle(Item->X(), Item->Y(), Item->X() + Item->Width() - 1, Item->Y() + Item->Height() - 1, Item->Bg());
+ mOsd->DrawRectangle(Item->X() + 2, Item->Y() + 2, Item->X() + (Item->Width() * current / total) - 3, Item->Y() + Item->Height() - 3, Item->Fg());
+ } else {
+ mOsd->DrawRectangle(Item->X(), Item->Y(), Item->X() + Item->Width() - 3, Item->Y() + Item->Height() - 3, Item->Bg());
+ mOsd->DrawRectangle(Item->X() + 2, Item->Y() + 2, Item->X() + Item->Width() - 3, Item->Y() + (Item->Height() * current / total) - 3, Item->Fg());
+ }
+ }
+}
+
+void cText2SkinRender::DisplayReplayTitle(cText2SkinItem *Item) {
+ if (mReplayTitle)
+ DrawTextTransparent(mOsd, Item->X(), Item->Y(), mReplayTitle, Item->Fg(), Item->Bg(), SkinFont(Item), Item->Width(), Item->Height(), Item->Align());
+}
+
+void cText2SkinRender::DisplayMenuItems(cText2SkinItem *Item) {
+ cText2SkinItem *area = mData->Get(itemMenuArea);
+ cText2SkinItem *current = mData->Get(itemMenuCurrent);
+ int xoffs = area->X();
+ int yoffs = area->Y();
+
+ if (Item->X() != -1)
+ xoffs += Item->X();
+ if (Item->Y() != -1)
+ yoffs += Item->Y();
+
+ printf("menu items\n");
+
+ int index = 0;
+ while (yoffs < area->Height() && index < (int)mItems.size()) {
+ if (index == mCurrent)
+ DrawTextTransparent(mOsd, xoffs + current->X(), yoffs + current->Y(), mItems[index].mName, current->Fg(), current->Bg(), SkinFont(Item), current->Width(), current->Height(), current->Align());
+ else
+ DrawTextTransparent(mOsd, xoffs + Item->X(), yoffs + Item->Y(), mItems[index].mName, Item->Fg(), Item->Bg(), SkinFont(Item), Item->Width(), Item->Height(), Item->Align());
+ yoffs += Item->Height();
+ ++index;
+ }
+}
diff --git a/render.h b/render.h
new file mode 100644
index 0000000..4b19d47
--- /dev/null
+++ b/render.h
@@ -0,0 +1,98 @@
+/*
+ * $Id: render.h,v 1.1.1.1 2004/05/23 00:08:03 lordjaxom Exp $
+ */
+
+#ifndef VDR_TEXT2SKIN_RENDER_H
+#define VDR_TEXT2SKIN_RENDER_H
+
+#include <vdr/osd.h>
+#include <vdr/skins.h>
+#include "data.h"
+#include <vector>
+
+using std::vector;
+
+class cChannel;
+class cEvent;
+
+class cText2SkinRender {
+ friend class cText2SkinDisplayChannel;
+ friend class cText2SkinDisplayVolume;
+ friend class cText2SkinDisplayReplay;
+ friend class cText2SkinDisplayMessage;
+ friend class cText2SkinDisplayMenu;
+
+private:
+ cText2SkinData *mData;
+ eSkinSection mSection;
+ cOsd *mOsd;
+
+ // TODO: rename or restructure items
+ // channel display
+ const cChannel *mChannel;
+ int mNumber;
+ const cEvent *mPresent;
+ const cEvent *mFollowing;
+
+ // volume display
+ int mVolumeCurrent;
+ int mVolumeTotal;
+ bool mVolumeMute;
+
+ // replay display
+ const char *mReplayTitle;
+ bool mReplayPlay;
+ bool mReplayForward;
+ int mReplaySpeed;
+ int mReplayCurrent;
+ int mReplayTotal;
+ const char *mReplayJump;
+
+ // message display
+ eMessageType mMessageType;
+ const char *mMessageText;
+
+ // menu
+ struct MenuItem {
+ const char *mName;
+ bool mSelectable;
+ bool operator!=(const MenuItem &b) { return b.mName != mName || b.mSelectable != mSelectable; }
+ };
+ const char *mTitle;
+ vector<MenuItem> mItems;
+ int mCurrent;
+
+protected:
+ void DisplayBackground(cText2SkinItem *Item);
+ void DisplayLogo(cText2SkinItem *Item);
+ void DisplayText(cText2SkinItem *Item);
+ void DisplayDateTime(cText2SkinItem *Item);
+ void DisplayDate(cText2SkinItem *Item);
+ void DisplayTime(cText2SkinItem *Item);
+ void DisplayChannelNumberName(cText2SkinItem *Item);
+ void DisplayChannelNumber(cText2SkinItem *Item);
+ void DisplayChannelName(cText2SkinItem *Item);
+ void DisplayRectangle(cText2SkinItem *Item);
+ void DisplayEllipse(cText2SkinItem *Item);
+ void DisplayTimebar(cText2SkinItem *Item);
+ void DisplayPresentTime(cText2SkinItem *Item);
+ void DisplayPresentTitle(cText2SkinItem *Item);
+ void DisplayPresentShortText(cText2SkinItem *Item);
+ void DisplayFollowingTime(cText2SkinItem *Item);
+ void DisplayFollowingTitle(cText2SkinItem *Item);
+ void DisplayFollowingShortText(cText2SkinItem *Item);
+ void DisplaySymbol(cText2SkinItem *Item);
+ void DisplayVolumebar(cText2SkinItem *Item);
+ void DisplayMute(cText2SkinItem *Item);
+ void DisplayProgressbar(cText2SkinItem *Item);
+ void DisplayReplayTitle(cText2SkinItem *Item);
+ void DisplayMenuItems(cText2SkinItem *Item);
+
+public:
+ cText2SkinRender(cText2SkinData *Data, eSkinSection Section);
+ ~cText2SkinRender();
+
+ void Flush(void);
+};
+
+#endif // VDR_TEXT2SKIN_RENDER_H
diff --git a/text2skin.c b/text2skin.c
new file mode 100644
index 0000000..19777aa
--- /dev/null
+++ b/text2skin.c
@@ -0,0 +1,51 @@
+/*
+ * text2skin.c: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: text2skin.c,v 1.2 2004/05/23 00:23:12 lordjaxom Exp $
+ */
+
+#include <vdr/plugin.h>
+#include "loader.h"
+
+static const char *VERSION = "0.0.1-pre1";
+static const char *DESCRIPTION = "Loader for text-based skins";
+
+class cText2SkinPlugin : public cPlugin {
+private:
+public:
+ cText2SkinPlugin(void);
+ virtual ~cText2SkinPlugin();
+ virtual const char *Version(void) { return VERSION; }
+ virtual const char *Description(void) { return DESCRIPTION; }
+ virtual bool Start(void);
+ virtual cMenuSetupPage *SetupMenu(void);
+ virtual bool SetupParse(const char *Name, const char *Value);
+ };
+
+cText2SkinPlugin::cText2SkinPlugin(void)
+{
+}
+
+cText2SkinPlugin::~cText2SkinPlugin()
+{
+}
+
+bool cText2SkinPlugin::Start(void)
+{
+ cText2SkinLoader::Start();
+ return true;
+}
+
+cMenuSetupPage *cText2SkinPlugin::SetupMenu(void)
+{
+ return NULL;
+}
+
+bool cText2SkinPlugin::SetupParse(const char *Name, const char *Value)
+{
+ return false;
+}
+
+VDRPLUGINCREATOR(cText2SkinPlugin); // Don't touch this!