diff options
author | lordjaxom <lordjaxom> | 2004-05-23 00:35:46 +0000 |
---|---|---|
committer | lordjaxom <lordjaxom> | 2004-05-23 00:35:46 +0000 |
commit | d309055320433e5fd899de53dc688d679609e6db (patch) | |
tree | ee3c3c97b3881f1e35e0da745b9571d11c0b6ac2 | |
download | vdr-plugin-text2skin-d309055320433e5fd899de53dc688d679609e6db.tar.gz vdr-plugin-text2skin-d309055320433e5fd899de53dc688d679609e6db.tar.bz2 |
- Initial revision.v0.0.1-pre1
-rw-r--r-- | COPYING | 340 | ||||
-rw-r--r-- | HISTORY | 6 | ||||
-rw-r--r-- | Makefile | 90 | ||||
-rw-r--r-- | README | 11 | ||||
-rw-r--r-- | SKINS | 314 | ||||
-rw-r--r-- | bitmap.c | 63 | ||||
-rw-r--r-- | bitmap.h | 22 | ||||
-rw-r--r-- | common.c | 71 | ||||
-rw-r--r-- | common.h | 14 | ||||
-rw-r--r-- | data.c | 196 | ||||
-rw-r--r-- | data.h | 125 | ||||
-rw-r--r-- | display.c | 236 | ||||
-rw-r--r-- | display.h | 95 | ||||
-rw-r--r-- | loader.c | 79 | ||||
-rw-r--r-- | loader.h | 32 | ||||
-rw-r--r-- | render.c | 370 | ||||
-rw-r--r-- | render.h | 98 | ||||
-rw-r--r-- | text2skin.c | 51 |
18 files changed, 2213 insertions, 0 deletions
@@ -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. @@ -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* *~ @@ -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: @@ -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 @@ -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; +} @@ -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! |