diff options
author | Dieter Hametner <dh (plus) vdr (at) gekrumbel (dot) de> | 2007-06-03 22:18:54 +0000 |
---|---|---|
committer | Dieter Hametner <dh (plus) vdr (at) gekrumbel (dot) de> | 2007-06-03 22:18:54 +0000 |
commit | cd260aabdb23fd97d9cb8b0105e61d90ca844f01 (patch) | |
tree | dac9b3f1a903dac9510974f443e0b376d27e6252 | |
parent | 41687a7bbe9c8d304b805a9a5f7e14101f1d75a5 (diff) | |
download | vdr-plugin-live-cd260aabdb23fd97d9cb8b0105e61d90ca844f01.tar.gz vdr-plugin-live-cd260aabdb23fd97d9cb8b0105e61d90ca844f01.tar.bz2 |
- general CSS based themeing support.
- added setup option to select theme.
- added search scheme for themable images and stylesheets.
- added marine (default) and redwine theme.
- documented new features. All developers must read
doc/dev-conventions.txt
34 files changed, 1262 insertions, 82 deletions
diff --git a/css/styles.css b/css/styles.css index 3bda69a..2f89a67 100644 --- a/css/styles.css +++ b/css/styles.css @@ -124,7 +124,7 @@ div.domTTepg { div.menu { background: #000057 url(menu_line_bg.png) repeat-x; - min-height: 30px; + min-height: 27px; margin: 0; padding: 0 0 0 10px; line-height: 20px; @@ -204,7 +204,7 @@ div.pagemenu span { div.pagemenu span.sep { text-decoration: none; - color: grey; + color: #C0C1DA; font-weight: lighter; padding: 5px; } diff --git a/doc/ChangeLog b/doc/ChangeLog index 69bac21..078e35c 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,16 +1,28 @@ +2007-06-03 Dieter Hametner <dieter@air.mittelstation.de> + + Added CSS based themeing support. For details please read + doc/css-themeing.txt and doc/dev-conventions.txt. + * setup.h, setup.cpp, setup.ecpp: added setup for theme and + selection of theme. + * pages/*.ecpp: added support for themable images. + * tntconfig.cpp: cascaded search for images, to support themeing. + 2007-06-03 Christian Wieninger <cwieninger at gmx dot de> - Setup includes now a local net mask specifying the address range without - necessary login (#321) + + Setup includes now a local net mask specifying the address range + without necessary login (#321) 2007-06-02 Christian Wieninger <cwieninger at gmx dot de> + required version of VDR is now >= 1.4.0-2 2007-06-01 Sascha Volkenandt <sascha at akv-soft dot de> - The detection of featured plugins was uniformed. The display in the about - box now reads "active: <version>" or "required: <version>" + The detection of featured plugins was uniformed. The display in + the about box now reads "active: <version>" or "required: + <version>" -2007-06-01 Dieter Hametner <dh+vdr@gekrumbel.de> +2007-06-01 Dieter Hametner <dh+vdr at gekrumbel dot de> These changes fix bug entry #339 * css-themeing.txt: describe how to do css themeing. @@ -26,6 +38,6 @@ unrecorded Sascha Volkenandt <sascha at akv-soft dot de> - Due to the introduction of a uniform header for C++ standard extenstions, - the boost library is now only necessary if the used g++ compiler version - is less than 4.0 + Due to the introduction of a uniform header for C++ standard + extenstions, the boost library is now only necessary if the used + g++ compiler version is less than 4.0 diff --git a/doc/css-themeing.txt b/doc/css-themeing.txt index be84e26..3148838 100644 --- a/doc/css-themeing.txt +++ b/doc/css-themeing.txt @@ -3,18 +3,111 @@ How to do live theming with CSS. Live supports CSS theming. While the structure of the html pages is given by the plugin, there is the possibility to change the look -through CSS. - -Currently a predefined, compiled into the plugin stylesheet 'styles.css' is -delivered first. Then a stylesheet 'css/siteprefs.css' is sent to the -browser. 'css/siteprefs.css' is a normal file that is found in -USRDIR. The default of USRDIR is /usr/share/vdr-plugin-live. This -can be changed at compile time by setting the USRDIR variable -(i.E. USRDIR=/tmp/live make) - -One of the next steps will be a mechanism to select additional style -files and images through a theme setting in vdr. The different themes -will be also located in theme related subdirs beneath USRDIR. +through CSS and exchanged images. + + +Themable resources +------------------ + +CSS stylesheets and referenced images are themable. That means a theme +can replace the icons and background images in the markup. + + +Access scheme for the css stylesheets +------------------------------------- + +Each live page requests at least three stylesheets in the following +order: + + 1. 'styles.css' (the build in stylesheet) is requested. + 2. The theme master stylesheet 'theme.css' is requested. + 3. A site preferences stylesheet is requested ('siteprefs.css') + + +Location for the stylesheets +---------------------------- + +The initial stylesheet 'styles.css' provides a basic layout. It is a +builtin stylesheet and can not be altered after live is compiled and +installed. + +The theme stylesheed 'theme.css' is requested through following url: + + themes/<themename>/css/theme.css + +The site preference stylesheet is requested through this url: + + css/siteprefs.css + + +Access scheme for themable images +--------------------------------- + +All themable images in the pages, that live delivers to the browser are +accessed through the url + + themes/<themename>/img/<imagename> + +If a image is not found under that url, the image is searched in + common/img/<imagename> + +And if not found there, an attempt to deliver a built in image is taken. + + +Location of the resources in the file system +-------------------------------------------- + +All themable content must be present in the directory specified by +USRDIR. The default USRDIR is /usr/share/vdr-plugin-live. This can be +changed at compile time by setting the USRDIR variable +(i.E. USRDIR=/tmp/live make). + +That means all themes must reside in USRDIR/themes. + + +Structure of a theme package +---------------------------- + +A theme package consists of directory named after the theme name. It +must contain the subdirectories 'css' and 'img'. Under css and img no +other subdirectories are allowed for security reasons (see below). + +In the subdirectory css a stylesheet theme.css must exist in oder to +override or extend the already defined styles from 'styles.css'. + +Additional images referenced through the stylesheet and images +replacing the default images go to the 'img' subdirectory. Replacing +images must have the same name like the image to be replaced. + +The live distribution comes with a few predefinded theme packages. You +should take look into them to better understand this structure. + + +Selecting a theme in live +------------------------- + +In the live setup page, the user can select the desired theme. When +the settings are saved the selected themes become active. Live detects +the available themes dynamicaly by scanning the 'themes' directory in +USERDIR for available themes and creates the select box from this +information. + +So the installation of a new theme is easyly done by unpacking a +theme-archive in USRDIR/themes. This assumes the theme-archive follows +the structure of a theme package as described above. + + +Security provisions +------------------- + +Live will map every url starting with themes/<themename>/css or +themes/<themename>/img to exactly these directories under USRDIR. That +means any path components after 'img' or 'css' are discarded. Only the +basename of the url is appended to these directories. This is to +prevent possible malicous requests to other locations in the +filesystem by adding '..' to the request path. The downside of this +is, that no additional directories below 'img' and 'css' are possible +for the theme designer. User Contribution diff --git a/doc/dev-conventions.txt b/doc/dev-conventions.txt index c3472fd..07d026d 100644 --- a/doc/dev-conventions.txt +++ b/doc/dev-conventions.txt @@ -1,4 +1,7 @@ -This file contains some guidlines for developers about what to obey +Live development guidelines +=========================== + +This file contains some guidelines for developers about what to obey when adding new functionality to live plugin. First of all please look at the existing code and how it was done @@ -8,12 +11,15 @@ We want to support a broad range of browsers. On one side are hand held devices like WEB-enabled PDAs or mobile phones. They often lack full grown support for ECMAScript and have small screen sizes. The other extreme are the desktop browsers like FireFox, Konqueror, Opera and -perhabs IE (if the 'powers that be' make him more CSS compliant). -Here WEB 2.0 featuers can improve the users experience. +perhaps IE (if the 'powers that be' make him more CSS compliant). +Here WEB 2.0 features can improve the users experience. + + +With or without ECMAScript +-------------------------- -In the future some themeing in live might help to cover this broad -range. Meanwhile we suggest the following rule to activate -functionality with and without ECMAScript support: +Since not all browsers support ECMAScript, we suggest the following +rule to activate functionality with and without ECMAScript support: Use anchors analog to this example @@ -23,3 +29,27 @@ Use anchors analog to this example to retrieve and display extra information either in a WEB 2.0 fashion in an popup box or on a separte page in a html fashion. + +Themeing +-------- + +Current CSS based themeing in live depends on additional stylesheets +and a configurable location to retrieve images from (see +css-themeing.txt). + +Developers must use the <& pageelems.stylesheets &> component in their +pages to include both the default and the themed stylesheet. This is +the easy part, because stylesheets are referred in the header at a +central location. + +More difficult is the access to images, which is spread around the +pages at the corresponding locations. To support this, a new method in +the live Setup class (see file setup.h) has been added. It is called +'GetThemedLink'. For every image, that might be customized, you must +use a img tag according to this example: + + <img src="<$ LiveSetup().GetThemedLink("img", "<imagename>") $>" + alt="someimage" /> + +Please take a look in the existing ecpp pages for additional usage +examples. diff --git a/filecache.h b/filecache.h index 5c1e83d..eaf9739 100644 --- a/filecache.h +++ b/filecache.h @@ -42,11 +42,11 @@ public: ptr_type get( key_type const& key ) { cMutexLock lock( &m_mutex ); - dsyslog( "vdrlive::FileCache::get( %s )", key.c_str() ); - dsyslog( "vdrlive::FileCache had %u entries (weight: %u)", count(), weight() ); + // dsyslog( "vdrlive::FileCache::get( %s )", key.c_str() ); + // dsyslog( "vdrlive::FileCache had %u entries (weight: %u)", count(), weight() ); ptr_type result = base_type::get( key ); - dsyslog( "vdrlive::FileCache now has %u entries (weight: %u)", count(), weight() ); - dsyslog( "vdrlive::FileCache::get( %s ) = %p", key.c_str(), result.get() ); + // dsyslog( "vdrlive::FileCache now has %u entries (weight: %u)", count(), weight() ); + // dsyslog( "vdrlive::FileCache::get( %s ) = %p", key.c_str(), result.get() ); return result; } diff --git a/pages/content.ecpp b/pages/content.ecpp index 61b8100..8f3cbbb 100644 --- a/pages/content.ecpp +++ b/pages/content.ecpp @@ -18,10 +18,10 @@ bool logged_in(false); string mime("image/png"); if (request.getArgsCount() > 0) { mime = request.getArg(0); - dsyslog("vdrlive::content found mime arg (%s)", mime.c_str()); + // dsyslog("vdrlive::content found mime arg (%s)", mime.c_str()); } reply.setContentType(mime); -dsyslog("vdrlive::content::mimetype(%s)", mime.c_str()); +// dsyslog("vdrlive::content::mimetype(%s)", mime.c_str()); // FileCache::ptr_type f = LiveFileCache().get("/tmp/live/" + request.getPathInfo()); string path(request.getPathInfo()); diff --git a/pages/edit_timer.ecpp b/pages/edit_timer.ecpp index cc51f9d..176db0e 100644 --- a/pages/edit_timer.ecpp +++ b/pages/edit_timer.ecpp @@ -183,7 +183,7 @@ if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html"); <label for="wday_tue"><$ tr("Tuesday") $></label> </div> <div class="dotted"> - <input id="wdry_wed" type="checkbox" name="wday_wed" value="1" <{ reply.out() << ( wday_wed ? "checked=\"checked\"" : "" ); }> /> + <input id="wday_wed" type="checkbox" name="wday_wed" value="1" <{ reply.out() << ( wday_wed ? "checked=\"checked\"" : "" ); }> /> <label for="wday_wed"><$ tr("Wednesday") $></label> </div> <div class="dotted"> diff --git a/pages/login.ecpp b/pages/login.ecpp index c3863ff..70fe7d8 100644 --- a/pages/login.ecpp +++ b/pages/login.ecpp @@ -45,7 +45,7 @@ if (logged_in || !LiveSetup().UseAuth()) return reply.redirect(LiveSetup().GetSt <div style="width: 350px; margin: 0 auto; text-align: center; padding: 20px"> <div class="boxheader"><div><div><$ tr("VDR Live Login") $></div></div></div> <div style="border: 1px solid black; padding: 15px"> - <img src="logo_login.png" alt="VDR Live"></img> + <img src="<$ LiveSetup().GetThemedLink("img", "logo_login.png") $>" alt="VDR Live"></img> <form name="auth"> <input type="hidden" name="action" value="login" /> <table class="login"> diff --git a/pages/pageelems.ecpp b/pages/pageelems.ecpp index 928e7b5..c8ac171 100644 --- a/pages/pageelems.ecpp +++ b/pages/pageelems.ecpp @@ -24,6 +24,7 @@ using namespace vdrlive; <%def stylesheets> <link rel="stylesheet" type="text/css" href="styles.css"/> +<link rel="stylesheet" type="text/css" href="<$ LiveSetup().GetThemedLink("css", "theme.css") $>"/> <link rel="stylesheet" type="text/css" href="css/siteprefs.css"/> </%def> @@ -31,9 +32,8 @@ using namespace vdrlive; <%def logo> <div class="page_header"> - -<a href="<$ LiveSetup().GetStartScreenLink()$>"> -<img src="logo.png" alt="VDR Live!" class="logo"></img></a> +<a href="<$ LiveSetup().GetStartScreenLink()$>"> +<img src="<$ LiveSetup().GetThemedLink("img", "logo.png") $>" alt="VDR Live!" class="logo"></img></a> <& infobox &> </div> <div style="clear: both"></div> @@ -54,7 +54,7 @@ using namespace vdrlive; </div> <div class="st_controls"> <div class="st_update"> - <a href="javascript:LiveStatusToggleUpdate()" <& tooltip.hint text=(tr("Stop updates")) &>><img id="statusReloadBtn" src="stop_update.png" alt="" /></a> + <a href="javascript:LiveStatusToggleUpdate()" <& tooltip.hint text=(tr("Stop updates")) &>><img id="statusReloadBtn" src="<$ LiveSetup().GetThemedLink("img", "stop_update.png") $>" alt="" /></a> </div> <div id="infobox_recording_buttons" style="display: none"> <& ajax_action_href action=("stop_recording") id=("infobox_stop") image=("stop.png") tip=(tr("stop playback")) &> @@ -111,10 +111,10 @@ using namespace vdrlive; if (timer) { </%cpp> <a href="edit_timer.html?timerid=<$ LiveTimerManager().GetTimers().GetTimerId(*timer) $>"> - <img src="record_timer.png" alt="" <& tooltip.hint text=(tr("Edit this")) &> /> + <img src="LiveSetup().GetThemedLink("img", "record_timer.png") $>" alt="" <& tooltip.hint text=(tr("Edit this")) &> /> <%cpp> } else { </%cpp> <a href="edit_timer.html?channelid=<$ channelid $>&eventid=<$ eventid $>"> - <img src="record.png" alt="" <& tooltip.hint text=(tr("Record this")) &> /> + <img src="<$ LiveSetup().GetThemedLink("img", "record.png") $>" alt="" <& tooltip.hint text=(tr("Record this")) &> /> <%cpp> } </%cpp> </a> </%def> @@ -137,7 +137,7 @@ using namespace vdrlive; string alt; string id; </%args> -<%cpp> { </%cpp> <a <%cpp> if (!id.empty()) { </%cpp> id="<$ id $>" <%cpp> } </%cpp><& hide_element hide=(!id.empty()) &> href="javascript:LiveSimpleAjaxRequest('<$ action $>.xml', 'param', '<$ param $>');" <%cpp>if (!tip.empty()) { </%cpp><& tooltip.hint text=(tip) &> <%cpp> } </%cpp>><img src="<$ image $>" alt="<$ alt $>"></img></a> <%cpp> } </%cpp> +<%cpp> { </%cpp> <a <%cpp> if (!id.empty()) { </%cpp> id="<$ id $>" <%cpp> } </%cpp><& hide_element hide=(!id.empty()) &> href="javascript:LiveSimpleAjaxRequest('<$ action $>.xml', 'param', '<$ param $>');" <%cpp>if (!tip.empty()) { </%cpp><& tooltip.hint text=(tip) &> <%cpp> } </%cpp>><img src="<$ LiveSetup().GetThemedLink("img", image) $>" alt="<$ alt $>"></img></a> <%cpp> } </%cpp> </%def> <# ---------------------------------------------------------------------- #> @@ -205,7 +205,7 @@ using namespace vdrlive; <{ Features< features::epgsearch >& epgsearch = LiveFeatures< features::epgsearch >(); }> - <img align="center" src="<$ epgsearch.Recent() ? "" : "in" $>active.png"/> EPGsearch + <img align="center" src="<$ LiveSetup().GetThemedLink("img", epgsearch.Recent() ? "active.png" : "inactive.png") $>"/> EPGsearch % if ( epgsearch.Recent() ) { (<$ tr("active") $>: <$ epgsearch.Version() $>) % } else { diff --git a/pages/recordings.ecpp b/pages/recordings.ecpp index b1b6b55..6695925 100644 --- a/pages/recordings.ecpp +++ b/pages/recordings.ecpp @@ -146,7 +146,7 @@ for (iter = recordingsTree.begin(path); iter != end; ++iter) { <%args> string archived; </%args> -<img src="on_dvd.png" alt="on_dvd" <& tooltip.hint text=(archived) &> /> +<img src="<$ LiveSetup().GetThemedLink("img", "on_dvd.png") $>" alt="on_dvd" <& tooltip.hint text=(archived) &> /> </%def> <# ---------------------------------------------------------------------- #> @@ -159,7 +159,7 @@ for (iter = recordingsTree.begin(path); iter != end; ++iter) { string folderimg = "folder_closed.png"; </%args> <div class="recording_item" onclick="Toggle(this)"> - <div class="recording_imgs"><%cpp> reply.out() << StringRepeat(level, "<img src=\"transparent.png\" alt=\"\" width=\"16px\" height=\"16px\" />"); </%cpp><img class="recording_expander" src="<$ collapseimg $>" alt="" /><img class="recording_folder" src="<$ folderimg $>" alt="" /></div> + <div class="recording_imgs"><%cpp> reply.out() << StringRepeat(level, "<img src=\"transparent.png\" alt=\"\" width=\"16px\" height=\"16px\" />"); </%cpp><img class="recording_expander" src="<$ LiveSetup().GetThemedLink("img", collapseimg) $>" alt="" /><img class="recording_folder" src="<$ LiveSetup().GetThemedLink("img", folderimg) $>" alt="" /></div> <div class="recording_spec"> <div class="recording_name"><$ name $></div> </div> @@ -183,7 +183,7 @@ for (iter = recordingsTree.begin(path); iter != end; ++iter) { string archiveId; </%args> <div class="recording_item"> - <div class="recording_imgs"><%cpp> reply.out() << StringRepeat(level + 1, "<img src=\"transparent.png\" alt=\"\" width=\"16px\" height=\"16px\" />"); </%cpp><%cpp> if (!archived.empty()) { </%cpp><& archived_disc archived=(archived) &><%cpp> } else { </%cpp><img src="movie.png" alt="movie" /><%cpp> } </%cpp></div> + <div class="recording_imgs"><%cpp> reply.out() << StringRepeat(level + 1, "<img src=\"transparent.png\" alt=\"\" width=\"16px\" height=\"16px\" />"); </%cpp><%cpp> if (!archived.empty()) { </%cpp><& archived_disc archived=(archived) &><%cpp> } else { </%cpp><img src="<$ LiveSetup().GetThemedLink("img", "movie.png") $>" alt="movie" /><%cpp> } </%cpp></div> <div class="recording_spec"> <div class="recording_day" style="width: <$ dayLen $>"><$ day $></div> <div class="recording_date"><$ FormatDateTime(tr("%b %d %y"), startTime) $></div> @@ -203,8 +203,8 @@ for (iter = recordingsTree.begin(path); iter != end; ++iter) { <%cpp> } </%cpp> - <img src="edit.png" alt="" /> - <img src="del.png" alt="" /> + <img src="<$ LiveSetup().GetThemedLink("img", "edit.png") $>" alt="" /> + <img src="<$ LiveSetup().GetThemedLink("img", "del.png") $>" alt="" /> </div> <%cpp> if (! archived.empty()) { diff --git a/pages/remote.ecpp b/pages/remote.ecpp index 12850f0..e4a7826 100644 --- a/pages/remote.ecpp +++ b/pages/remote.ecpp @@ -80,11 +80,11 @@ if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html"); <{ if (!LiveGrabImageManager().CanGrab()) { }> bloek <{ } else { }> - <img src="screenshot.jpg" name="vdrlive" /><br /> + <img src="<$ LiveSetup().GetThemedLink("img", "screenshot.jpg") $>" name="vdrlive" /><br /> <{ } }> </div> <div> - <img src="remotecontrol.jpg" width="162" height="363" border="0" usemap="#remote" alt="" /> + <img src="<$ LiveSetup().GetThemedLink("img", "remotecontrol.jpg") $>" width="162" height="363" border="0" usemap="#remote" alt="" /> <map name="remote"> <area href="#" shape="circle" coords="37,36,10" alt="Power" onclick="KeyPress(<$ kPower $>)" nohref="nohref" alt="" /> <area href="#" shape="rect" coords="27,60,59,75" alt="1" onclick="KeyPress(<$ k1 $>)" nohref="nohref" alt="" /> diff --git a/pages/schedule.ecpp b/pages/schedule.ecpp index 5357b3d..fd5ece1 100644 --- a/pages/schedule.ecpp +++ b/pages/schedule.ecpp @@ -109,9 +109,9 @@ if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html"); <tr class="<? active_line ? "active" ?>"> <td style="border-left: 1px solid black"><& pageelems.event_timer channelid=(channel_id) eventid=(event) &> % if ( LiveFeatures< features::epgsearch >().Recent() ) { - <a href="searchresults.html?searchplain=<$ StringUrlEncode(title) $>"><img src="/search.png" border="0" alt="" <& tooltip.hint text=(tr("Search for repeats.")) &>></img></a> + <a href="searchresults.html?searchplain=<$ StringUrlEncode(title) $>"><img src="<$ LiveSetup().GetThemedLink("img", "search.png") $>" border="0" alt="" <& tooltip.hint text=(tr("Search for repeats.")) &>></img></a> % } - <a href="http://akas.imdb.com/Tsearch?title=<$ StringUrlEncode(title) $>"><img src="imdb.png" border="0" alt="" <& tooltip.hint text=(tr("Find more at the Internet Movie Database.")) &>></img></a> + <a href="http://akas.imdb.com/Tsearch?title=<$ StringUrlEncode(title) $>"><img src="<$ LiveSetup().GetThemedLink("img", "imdb.png") $>" border="0" alt="" <& tooltip.hint text=(tr("Find more at the Internet Movie Database.")) &>></img></a> </td> <td><$ start $> - <$ end $></td> <td> diff --git a/pages/searchtimers.ecpp b/pages/searchtimers.ecpp index 4a39402..296a110 100644 --- a/pages/searchtimers.ecpp +++ b/pages/searchtimers.ecpp @@ -66,14 +66,14 @@ if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html"); }> <tr> <td class="border" style="border-left: 1px solid black"></td> - <td><{ if(timer->UseAsSearchTimer()) { }><img src="arrow.png" alt=""></img><{ } }></td> + <td><{ if(timer->UseAsSearchTimer()) { }><img src="<$ LiveSetup().GetThemedLink("img", "arrow.png") $>" alt=""></img><{ } }></td> <td><$ timer->Search() $></td> <td><$ timer->ChannelText() $></td> <td><? timer->UseTime() ? timer->StartTimeFormatted()+" - "+timer->StopTimeFormatted() ?></td> - <td><a href="searchtimers.html?searchtimerid=<$ timer->Id() $>&action=toggle"><img src="<$ timer->UseAsSearchTimer() ? "active" : "inactive" $>.png" alt="<$ tr("Toggle search timer actions (in)active") $>" <& tooltip.hint text=(tr("Toggle search timer actions (in)active")) &>></img></a></td> - <td><a href="searchresults.html?searchtimerid=<$ timer->Id() $>"><img src="search.png" border="0" alt="<$ tr("Browse search timer results") $>" <& tooltip.hint text=(tr("Browse search timer results")) &>></img></a></td> - <td><a href="edit_searchtimer.html?searchtimerid=<$ timer->Id() $>"><img src="edit.png" alt="<$ tr("Edit search timer") $>" <& tooltip.hint text=(tr("Edit search timer")) &>></img></a></td> - <td><a href="searchtimers.html?searchtimerid=<$ timer->Id() $>&action=delete" onclick="return confirm('<$ tr("Delete this search timer?") $>')"><img src="del.png" alt="<$ tr("Delete search timer") $>" <& tooltip.hint text=(tr("Delete search timer")) &>></img></a></td> + <td><a href="searchtimers.html?searchtimerid=<$ timer->Id() $>&action=toggle"><img src="<$ LiveSetup().GetThemedLink("img", timer->UseAsSearchTimer() ? "active.png" : "inactive.png") $>" alt="<$ tr("Toggle search timer actions (in)active") $>" <& tooltip.hint text=(tr("Toggle search timer actions (in)active")) &>></img></a></td> + <td><a href="searchresults.html?searchtimerid=<$ timer->Id() $>"><img src="<$ LiveSetup().GetThemedLink("img", "search.png") $>" alt="<$ tr("Browse search timer results") $>" <& tooltip.hint text=(tr("Browse search timer results")) &>></img></a></td> + <td><a href="edit_searchtimer.html?searchtimerid=<$ timer->Id() $>"><img src="<$ LiveSetup().GetThemedLink("img", "edit.png") $>" alt="<$ tr("Edit search timer") $>" <& tooltip.hint text=(tr("Edit search timer")) &>></img></a></td> + <td><a href="searchtimers.html?searchtimerid=<$ timer->Id() $>&action=delete" onclick="return confirm('<$ tr("Delete this search timer?") $>')"><img src="<$ LiveSetup().GetThemedLink("img", "del.png") $>" alt="<$ tr("Delete search timer") $>" <& tooltip.hint text=(tr("Delete search timer")) &>></img></a></td> <td class="border" style="border-right: 1px solid black"></td> </tr> <{ diff --git a/pages/setup.ecpp b/pages/setup.ecpp index b099c0f..43c0de8 100644 --- a/pages/setup.ecpp +++ b/pages/setup.ecpp @@ -1,4 +1,5 @@ <%pre> +#include <vdr/tools.h> #include "setup.h" #include "tools.h" @@ -13,6 +14,7 @@ using namespace std; string pass; string times; string startscreen; + string theme; string localnetmask; </%args> <%session scope="global"> @@ -37,6 +39,7 @@ if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html"); } LiveSetup().SetTimes(times); LiveSetup().SetStartScreen(startscreen); + LiveSetup().SetTheme(theme); LiveSetup().SaveSetup(); } pageTitle = tr("Setup"); @@ -50,6 +53,7 @@ if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html"); useauth = LiveSetup().GetUseAuth(); times = LiveSetup().GetTimes(); startscreen = LiveSetup().GetStartScreen(); + theme = LiveSetup().GetTheme(); localnetmask = LiveSetup().GetLocalNetMask(); </%cpp> <& pageelems.doc_type &> @@ -130,6 +134,32 @@ if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html"); </tr> <tr> <td class="border" style="border-left: 1px solid black"></td> + <td class="label"><$ tr("Theme") $>:</td> + <td><select name="theme" size="1" id="theme"> +<%cpp> +{ + cReadDir d(USRDIR "/themes"); + struct dirent* e; + string parent(".."); + string current("."); + while ((e = d.Next())) { + if ((current == e->d_name) || (parent == e->d_name)) { + continue; + } + if (DT_DIR != e->d_type) { + continue; + } +</%cpp> + <option value="<$ e->d_name $>" <{ SELECTIF(theme == e->d_name) }>><$ e->d_name $></option> +<%cpp> + } +} +</%cpp> + </select></td> + <td class="border" style="border-right: 1px solid black"></td> + </tr> + <tr> + <td class="border" style="border-left: 1px solid black"></td> <td class="buttonpanel" colspan="2"> <button class="green" type="submit" name="save" onclick="return checksearch();"><$ tr("Save") $></button> </td> diff --git a/pages/timers.ecpp b/pages/timers.ecpp index dc67178..01eacc9 100644 --- a/pages/timers.ecpp +++ b/pages/timers.ecpp @@ -99,14 +99,14 @@ using namespace vdrlive; </%cpp> <tr> <td class="border" style="border-left: 1px solid black"></td> - <td><img src="<$ timerStateImg $>" alt=""></img></td> + <td><img src="<$ LiveSetup().GetThemedLink("img", timerStateImg) $>" alt=""></img></td> <td><a href="schedule.html?channel=<$ timer->Channel()->Number()$>"><$ timer->Channel()->Name() $></a></td> <td><$ FormatDateTime(tr("%I:%M %p"), timer->StartTime()) $></td> <td><$ FormatDateTime(tr("%I:%M %p"), timer->StopTime()) $></td> <td><$ timer->File() $></td> - <td><a href="timers.html?timerid=<$ timers.GetTimerId(*timer) $>&action=toggle"><img src="<$ (timer->Flags() & tfActive) ? "active" : "inactive" $>.png" alt="" <& tooltip.hint text=(tr("Toggle timer active/inactive")) &>></img></a></td> - <td><a href="edit_timer.html?timerid=<$ timers.GetTimerId(*timer) $>"><img src="edit.png" alt="" <& tooltip.hint text=(tr("Edit timer")) &>></img></a></td> - <td><a href="timers.html?timerid=<$ timers.GetTimerId(*timer) $>&action=delete"><img src="del.png" alt="" <& tooltip.hint text=(tr("Delete timer")) &>></img></a></td> + <td><a href="timers.html?timerid=<$ timers.GetTimerId(*timer) $>&action=toggle"><img src="<$ LiveSetup().GetThemedLink("img", (timer->Flags() & tfActive) ? "active.png" : "inactive.png") $>" alt="" <& tooltip.hint text=(tr("Toggle timer active/inactive")) &>></img></a></td> + <td><a href="edit_timer.html?timerid=<$ timers.GetTimerId(*timer) $>"><img src="<$ LiveSetup().GetThemedLink("img", "edit.png") $>" alt="" <& tooltip.hint text=(tr("Edit timer")) &>></img></a></td> + <td><a href="timers.html?timerid=<$ timers.GetTimerId(*timer) $>&action=delete"><img src="<$ LiveSetup().GetThemedLink("img", "del.png") $>" alt="" <& tooltip.hint text=(tr("Delete timer")) &>></img></a></td> <td class="border" style="border-right: 1px solid black"></td> </tr> <%cpp> diff --git a/pages/tooltip.ecpp b/pages/tooltip.ecpp index bdba57c..bd11415 100644 --- a/pages/tooltip.ecpp +++ b/pages/tooltip.ecpp @@ -1,3 +1,9 @@ +<%pre> +#include "setup.h" + +using namespace vdrlive; + +</%pre> <%def javascript> <%args> styleClass="domTThint"; @@ -44,12 +50,12 @@ domId; <%args> domId; </%args> - <a href="#void" onclick="domTT_close('<$ (domId + "_tip") $>')"><img src="close.png" alt="" /></a> + <a href="#void" onclick="domTT_close('<$ (domId + "_tip") $>')"><img src="<$ LiveSetup().GetThemedLink("img", "close.png") $>" alt="" /></a> </%def> <%def help> <%args> text; </%args> - <img src="help.png" onmouseover="domTT_close(domTT_lastOpened); domTT_activate(this, event, 'predefined', 'tipHint', 'content', '<$ text $>');"></img> + <img src="<$ LiveSetup().GetThemedLink("img", "help.png") $>" onmouseover="domTT_close(domTT_lastOpened); domTT_activate(this, event, 'predefined', 'tipHint', 'content', '<$ text $>');"></img> </%def> diff --git a/pages/whats_on.ecpp b/pages/whats_on.ecpp index d537262..09bb560 100644 --- a/pages/whats_on.ecpp +++ b/pages/whats_on.ecpp @@ -143,9 +143,9 @@ if (type == "now") { <& pageelems.ajax_action_href action="switch_channel" tip=(tr("Switch to this channel.")) param=(channel_id) image="zap.png" alt="" &> % } % if ( LiveFeatures< features::epgsearch >().Recent() ) { - <a href="searchresults.html?searchplain=<$ StringEscapeAndBreak(epgEvent->Title()) $>"><img src="search.png" border="0" alt="" <& tooltip.hint text=(tr("Search for repeats.")) &>></img></a> + <a href="searchresults.html?searchplain=<$ StringEscapeAndBreak(epgEvent->Title()) $>"><img src="<$ LiveSetup().GetThemedLink("img", "search.png") $>" alt="" <& tooltip.hint text=(tr("Search for repeats.")) &>></img></a> % } - <a href="http://akas.imdb.com/Tsearch?title=<$ StringUrlEncode(epgEvent->Title()) $>"><img src="imdb.png" border="0" alt="" <& tooltip.hint text=(tr("Find more at the Internet Movie Database.")) &>></img></a> + <a href="http://akas.imdb.com/Tsearch?title=<$ StringUrlEncode(epgEvent->Title()) $>"><img src="<$ LiveSetup().GetThemedLink("img", "imdb.png") $>" alt="" <& tooltip.hint text=(tr("Find more at the Internet Movie Database.")) &>></img></a> </div> <div> <div class="info"><$ (epgEvent->StartTime(tr("%I:%M %p"))) $> - <$ (epgEvent->EndTime(tr("%I:%M %p"))) $></div> @@ -166,9 +166,9 @@ if (type == "now") { <& pageelems.ajax_action_href action="switch_channel" tip=(tr("Switch to this channel.")) param=(channel_id) image="zap.png" alt="" &> % } % if ( LiveFeatures< features::epgsearch >().Recent() ) { - <a href="searchresults.html?searchplain=<$ StringUrlEncode(epgEvent->Title()) $>"><img src="/search.png" border="0" alt="" <& tooltip.hint text=(tr("Search for repeats.")) &>></img></a> + <a href="searchresults.html?searchplain=<$ StringUrlEncode(epgEvent->Title()) $>"><img src="<$ LiveSetup().GetThemedLink("img", "search.png") $>" border="0" alt="" <& tooltip.hint text=(tr("Search for repeats.")) &>></img></a> % } - <a href="http://akas.imdb.com/Tsearch?title=<$ StringUrlEncode(epgEvent->Title()) $>"><img src="imdb.png" border="0" alt="" <& tooltip.hint text=(tr("Find more at the Internet Movie Database.")) &>></img></a> + <a href="http://akas.imdb.com/Tsearch?title=<$ StringUrlEncode(epgEvent->Title()) $>"><img src="<$ LiveSetup().GetThemedLink("img", "imdb.png") $>" border="0" alt="" <& tooltip.hint text=(tr("Find more at the Internet Movie Database.")) &>></img></a> </td> <td> <div><$ (epgEvent->StartTime(tr("%I:%M %p"))) $> - <$ (epgEvent->EndTime(tr("%I:%M %p"))) $></div> @@ -77,6 +77,7 @@ bool Setup::ParseSetupEntry( char const* name, char const* value ) else if ( strcmp( name, "AdminPasswordMD5" ) == 0 ) m_adminPasswordMD5 = value; else if ( strcmp( name, "UserdefTimes" ) == 0 ) m_times = value; else if ( strcmp( name, "StartPage" ) == 0 ) m_startscreen = value; + else if ( strcmp( name, "Theme" ) == 0 ) m_theme = value; else if ( strcmp( name, "LocalNetMask" ) == 0 ) { m_localnetmask = value; } else if ( strcmp( name, "LastWhatsOnListMode" ) == 0 ) { m_lastwhatsonlistmode = value; } else return false; @@ -154,14 +155,14 @@ bool Setup::UseAuth() const bool Setup::CheckLocalNet(const std::string& ip) { // split local net mask in net and range - vector< string > parts = StringSplit( m_localnetmask, '/' ); + vector< string > parts = StringSplit( m_localnetmask, '/' ); if (parts.size() != 2) return false; - string net = parts[0]; + string net = parts[0]; - int range = lexical_cast< int >(parts[1]); + int range = lexical_cast< int >(parts[1]); // split net and ip addr in its 4 subcomponents - vector< string > netparts = StringSplit( net, '.' ); - vector< string > addrparts = StringSplit( ip, '.' ); + vector< string > netparts = StringSplit( net, '.' ); + vector< string > addrparts = StringSplit( ip, '.' ); if (netparts.size() != 4 || addrparts.size() != 4) return false; // to binary representation @@ -183,7 +184,7 @@ bool Setup::CheckLocalNet(const std::string& ip) string bin_net_range(bin_net.begin(), bin_net.begin() + range); string addr_net_range(bin_addr.begin(), bin_addr.begin() + range); m_islocalnet = (bin_net_range == addr_net_range); - + return m_islocalnet; } @@ -200,6 +201,7 @@ bool Setup::SaveSetup() } liveplugin->SetupStore("UserdefTimes", m_times.c_str()); liveplugin->SetupStore("StartPage", m_startscreen.c_str()); + liveplugin->SetupStore("Theme", m_theme.c_str()); liveplugin->SetupStore("LastWhatsOnListMode", m_lastwhatsonlistmode.c_str()); return true; } @@ -19,7 +19,7 @@ class cMenuSetupLive; class Setup { friend Setup& LiveSetup(); - friend class cMenuSetupLive; // friend declaration is not forward + friend class cMenuSetupLive; // friend declaration is not forward // declaration, although gcc 3.3 claims so public: @@ -39,10 +39,12 @@ public: std::string GetTimes() const { return m_times; } std::string GetStartScreen() const { return m_startscreen; } std::string GetStartScreenLink() const; + std::string GetTheme() const { return m_theme; } + std::string GetThemedLink(const std::string& type, const std::string& name) const { return "themes/" + GetTheme() + "/" + type + "/" + name; } std::string GetLocalNetMask() const { return m_localnetmask; }; bool GetIsLocalNet() const { return m_islocalnet; }; std::string GetLastWhatsOnListMode() const { return m_lastwhatsonlistmode; } - + void SetLastChannel(int lastChannel) { m_lastChannel = lastChannel; } void SetAdminLogin(std::string login) { m_adminLogin = login; } std::string SetAdminPassword(std::string password); @@ -50,16 +52,22 @@ public: void SetScrenshotInterval(int interval) { m_screenshotInterval = interval; } void SetTimes(std::string times) { m_times = times; } void SetStartScreen(std::string startscreen) { m_startscreen = startscreen; } + void SetTheme(std::string theme) { m_theme = theme; } void SetLocalNetMask(std::string localnetmask) { m_localnetmask = localnetmask; } void SetIsLocalNet(bool islocalnet) { m_islocalnet = islocalnet; } + void SetLastWhatsOnListMode(std::string mode) { m_lastwhatsonlistmode = mode; SaveSetup(); } + bool SaveSetup(); bool ParseCommandLine( int argc, char* argv[] ); char const* CommandLineHelp() const; bool ParseSetupEntry( char const* name, char const* value ); + + bool HaveEPGSearch(void); bool CheckLocalNet(const std::string& ip); + private: Setup(); Setup( Setup const& ); @@ -74,16 +82,17 @@ private: // setup options int m_lastChannel; int m_screenshotInterval; - + int m_useAuth; std::string m_adminLogin; std::string m_adminPasswordMD5; std::string m_times; std::string m_startscreen; + std::string m_theme; std::string m_localnetmask; bool m_islocalnet; std::string m_lastwhatsonlistmode; - + bool CheckServerPort(); bool CheckServerIps(); }; @@ -97,15 +106,15 @@ protected: virtual eOSState ProcessKey(eKeys Key); public: cMenuSetupLive(); - + private: int m_lastChannel; int m_screenshotInterval; - + int m_useAuth; char m_adminLogin[20]; char m_adminPassword[20]; - char m_tmpPassword[20]; + char m_tmpPassword[20]; std::string m_oldpasswordMD5; std::string m_newpasswordMD5; diff --git a/themes/marine/css/theme.css b/themes/marine/css/theme.css new file mode 100644 index 0000000..6d9c293 --- /dev/null +++ b/themes/marine/css/theme.css @@ -0,0 +1,5 @@ +/* ############################################## + # This is the theme file for the marine theme. + # It is empty because marine theme is the default live theme. + ############################################## +*/ diff --git a/themes/marine/img/zap.png b/themes/marine/img/zap.png Binary files differnew file mode 100644 index 0000000..d5d8628 --- /dev/null +++ b/themes/marine/img/zap.png diff --git a/themes/redwine/css/theme.css b/themes/redwine/css/theme.css new file mode 100644 index 0000000..33872df --- /dev/null +++ b/themes/redwine/css/theme.css @@ -0,0 +1,982 @@ +/* ###################### + # Globals + ###################### +*/ + +body { + margin: 0px; + padding: 0px; + font-size: 11px; + font-family: Verdana, Arial, Helvetica, sans-serif; +} + +table { + font-size: 11px; + font-family: Verdana, Arial, Helvetica, sans-serif; + margin: 0px; +} + +tr, td { + padding-top: 0px; + padding-bottom: 0px; +} + +input { + border: 1px solid #963B5F; + font-size: 11px; + font-family: Verdana, Arial, Helvetica, sans-serif; + background: #FEFEFE; + margin: 0; +} + +select { + border: 1px solid #963B5F; + font-size: 11px; + font-family: Verdana, Arial, Helvetica, sans-serif; +} + +img { + border: 0; +} + +/* ###################### + # global style properties + ###################### +*/ + +.bold { + font-weight: bold; +} + +/* ###################### + # Tooltip style for hints + ###################### +*/ + +div.domTThint { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 11px; + border: 1px solid #EBC94C; + background-color: #F4FFC3; + max-width: 35em; +} + +div.domTThint .caption { + font-weight: bold; +} + +div.domTThint .contents { + padding: 2px; +} + +/* ############################## + # Tooltip style for epg infos + ############################## +*/ + +div.domTTepg { + width: 66%; + border: none; +} + +.domTTepg div.epg_description { +} + +.domTTepg div.epg_content { + padding: 0; + margin: 0; + + border-left: 1px solid #000000; + border-right: 1px solid #000000; + border-bottom: 1px solid #000000; + background: white url(../img/bg_tools.png) top left repeat-y; +} + +.domTTepg div.epg_content div.epg_tools { + float: left; + width: 26px; + margin: 0; + padding: 0; + + text-align: center; + vertical-align: top; +} + +.domTTepg div.epg_content div div.progress div { + padding-left: 0px; +} + +.domTTepg div.epg_content div div { + padding-left: 35px; +} + +.domTTepg div.epg_content div.epg_tools img { + margin-top: 5px; +} + +.domTTepg div.boxheader div div a { +} + +/* ####################### + # Menue + ####################### +*/ + +div.menu { + background: #000057 url(../img/menu_line_bg.png) repeat-x; + min-height: 27px; + margin: 0; + padding: 0 0 0 10px; + line-height: 20px; + vertical-align: middle; + border-top: 1px solid black; + border-bottom: 1px solid black; + color: #FFE9FA; +} + +div.menu a { + text-decoration: none; + color: white; + font-weight: bold; +} + +a#login { + color: #F5FF2D; +} + +div.menu a.active { + text-decoration: none; + color: #FFDB88; + font-weight: bold; +} + + +div.menu a:hover { + text-decoration: underline; +} + +div.menu form { + display: inline; +} + +div.inhalt { + height: 200px; + width: 100% + overflow: auto; + padding: 10px; +} + +div.pagemenu { + margin-top: 2px; + padding-top: 6px; + background: #FFFFFF url(../img/bg_line.png) top repeat-x; +} + +div.pagemenu div { + padding-bottom: 6px; + background: #FFFFFF url(../img/bg_line_top.png) bottom repeat-x; +} + +div.pagemenu div div { + padding: 2px 0px 2px 10px; + background: #FFE9FA; + border-top: 1px solid #DA8DA8; + border-bottom: 1px solid #DA8DA8; +} + +div.pagemenu a { + text-decoration: none; + color: black; + font-weight: bold; +} + +div.pagemenu a.active { + text-decoration: none; + color: #984E79; + font-weight: bold; +} +div.pagemenu span { + text-decoration: none; + color: black; + font-weight: bold; + padding: 5px; +} + +div.pagemenu span.sep { + text-decoration: none; + color: #DA8DA8; + font-weight: lighter; + padding: 5px; +} + +/* ####################### + # Info Box (near logo) + ####################### +*/ +img.logo { + float: left; + margin-top: 5px; + margin-left: 5px; + margin-right: 25px; +} + +div#infobox { + float: left; + border: 1px solid #DA8DA8; + margin: 5px; + width: 320px; +} + +div#infobox div.st_header { + overflow: hidden; + padding: 1px 4px; + background: #FFE9FA; + border-bottom: 1px solid #DA8DA8; +} + +div#infobox div.st_header div.now { + float: right; +} + +div#infobox div.st_header div.caption { + float: left; + overflow: hidden; + font-weight: bold; +} + +div#infobox div.st_content { + overflow: hidden; + padding: 4px; + background: white url(../img/bg_line_top.png) top left repeat-x; +} + +div#infobox div.st_content div.duration { + float: right; +} + +div#infobox div.st_content div.name { + float: left; + overflow: hidden; + font-weight: bold; +} + +div#infobox div.st_controls { + overflow: hidden; + padding: 4px; +} + +div#infobox div.st_controls div.st_pbar { + padding-top: 4px; + float: right; +} + +div#infobox div.st_controls div { + float: left; +} + +div#infobox div.st_controls div.st_update { + padding-right: 5px; + border-right: 1px solid #DA8DA8; +} + +div#infobox div.st_controls div#infobox_recording_buttons { + padding-left: 5px; +} + +div#infobox div.st_controls div#infobox_channel_buttons { + padding-left: 5px; +} + +/* ####################### + # Head Box + ####################### +*/ + +div.head_box_l { + background-image: url(../img/bg_header_l.png); + background-position: top left; + background-repeat: no-repeat; + margin: 0; + margin-bottom: 2ex; + padding: 0; +} + +div.head_box_m { + background-image: url(../img/bg_header_h.png); + background-repeat: repeat-x; + margin: 3px; + padding: 0; +} + +div.head_box_r { + background-image: url(../img/bg_header_r.png); + background-position: top right; + background-repeat: no-repeat; + margin: -3px; + padding: 0; + padding-left: 0.5em; +} + +table.head_box_text { + color: #ffffff; + font-weight: bold; + padding: 0; + margin: 0; + height: 30px; +} + +button.smallbutton { + width: 51px; + height: 17px; + background-color: inherit; + background-image: url(../img/button_blue.png); + background-repeat: no-repeat; + color: #FFFFFF; + font-size: 11px; + border: 0px; + vertical-align: middle; + text-align: center; + cursor: pointer; +} + +button.green { + width: 100px; + height: 20px; + background-color: inherit; + background-image: url(../img/button_green.png); + background-repeat: no-repeat; + color: #FFFFFF; + font-size: 11px; + border: 0px; + vertical-align: middle; + text-align: center; + cursor: pointer; + padding-bottom: 3px; +} + +button.red { + width: 100px; + height: 20px; + background-color: inherit; + background-image: url(../img/button_red.png); + background-repeat: no-repeat; + color: #FFFFFF; + font-size: 11px; + border: 0px; + vertical-align: middle; + text-align: center; + cursor: pointer; + padding-bottom: 3px; +} + +button.blue { + width: 100px; + height: 20px; + background-color: inherit; + background-image: url(../img/button_blue.png); + background-repeat: no-repeat; + color: #FFFFFF; + font-size: 11px; + border: 0px; + vertical-align: middle; + text-align: center; + cursor: pointer; + padding-bottom: 3px; +} + +table td.buttonpanel { + text-align: right; +} + +/* ################ + # Event + ################ +*/ + +div.event { + width: 255px; + height: 255px; + padding: 0; + margin-right: 5px; + float: left; +} + +div.event div.station { + margin: 0; + padding: 0; + width: 255px; +} + +div.station div { + margin: 0; + padding: 0; + background: url(../img/bg_box_l.png) top left no-repeat; + height: 23px; +} + +div.station div div { + background: url(../img/bg_box_r.png) top right no-repeat; +} + +div.station div div div { + background: url(../img/bg_box_h.png) repeat-x; + vertical-align: middle; + text-align: left; + margin-right: 3px; + margin-left: 3px; + padding-left: 5px; + padding-top: 2px; + color: white; + font-weight: bold; +} + +div.station div div div a { + color: #ffffff; + font-weight: bold; + text-decoration: none; +} + +div.station div div div a:hover { + text-decoration: underline; +} + +td div.station { + vertical-align: middle; +} + +td div.station a { + color: black; + font-weight: bold; + text-decoration: none; +} + +td div.station a:hover { + text-decoration: underline; +} + +div.content { + width: 253px; + height: 220px; + padding: 0; + margin: 0; + + background: white url(../img/bg_tools.png) top left repeat-y; + border-left: 1px solid #000000; + border-right: 1px solid #000000; + border-bottom: 1px solid #000000; +} + +div.content div.tools { + float: left; + width: 26px; + height: 220px; + margin: 0; + padding: 0; + + text-align: center; + vertical-align: top; +} + +div.content div.tools img { + margin: 5px 2px; + border: 0px; +} + +div.content div { + padding-left: 15px; +} + +div.description { + margin: 5px; +} + +div.info { + text-align: right; + padding: 5px; +} + +div.progress { + overflow: hidden; + padding-right: 4px; +} + +div.progress div { + float: right; + padding: 0px; +} + +div.title { + font-weight: bold; + margin: 5px; +} + +div.short { + font-weight: normal; + margin: 5px; +} + +div.more { + margin: 5px; + font-weight: bold; + cursor: pointer; +} + +div.__progress { + overflow: hidden; + width: 100px; + height: 8px; + border: 1px solid #DA8DA8; +} + +div.__progress div.__elapsed { + float: left; + height: 8px; + background-color: #FFE9FA; +} + + +/* ############# + # Timers + ############# +*/ + +table.timers { + padding: 0; + margin: 0; + margin-top: 10px; +} + +table.timers tr td { + padding: 3px 7px 3px 3px; + background: url(../img/bg_line.png) bottom repeat-x; + border-bottom: 1px solid #DA8DA8; +} + +table.timers td.border { + padding: 0; + margin: 0; + width: 1px; +} + +table.timers tr.head td { + color: white; + font-weight: bold; + margin: 0; + padding: 0; + border-bottom: 1px solid black; +} + +table.timers tr.description td { + font-weight: bold; + background: #FFE9FA; +} + +table.timers a { + text-decoration: none; + color: black; + font-weight: bold; +} + + +/* + ############################## + # Schedule + ############################## +*/ + +table.schedule { + margin: 10px 0 0 0 ; + padding: 0; +} + +table.schedule tr td.head { + background: #963B5F; + color: white; + font-weight: bold; + margin: 0; + padding: 3px; +} + +table.schedule tr td { + vertical-align: top; + padding: 3px 7px 3px 3px; + background: url(../img/bg_line.png) bottom repeat-x; + border-bottom: 1px solid #DA8DA8; +} + +table.schedule tr td.day { + vertical-align: top; + padding: 0; + margin: 0; + border:none; +} + +table.schedule tr.active { + background: #DEE6EE; +} + +table.schedule div.more { + margin: 0px; + font-weight: bold; + cursor: pointer; +} + +/* + ############################## + # Blue Background Thingy + ############################## +*/ + +div.boxheader { + margin: 0; + padding: 0; + background: url(../img/bg_box_l.png) top left no-repeat; +} + +div.boxheader div { + background: url(../img/bg_box_r.png) top right no-repeat; +} + +div.boxheader div div { + background: url(../img/bg_box_h.png) repeat-x; + vertical-align: middle; + text-align: left; + margin-right: 3px; + margin-left: 3px; + padding-left: 5px; + padding-top: 2px; + color: white; + font-weight: bold; + height: 21px; + line-height: 20px; +} + +/* + ############################## + # Recordings + ############################## +*/ + +div.recordings { + border: 1px solid black; +} + +.recordings ul { + list-style-type: none; + padding: 0px; + margin: 0px; +} + +div.recording_item { + overflow: hidden; + background: url(../img/bg_line.png) bottom repeat-x; + border-bottom: 1px solid #DA8DA8; +} + +.recording_item div { + float: left; +} + +.recording_item div.recording_imgs{ + margin-right: 0.5em; +} + +.recording_item div.recording_spec { + padding-top: 0.5ex; +} + +.recording_item div.recording_day { +} + +.recording_item div.recording_date { + width: 5.25em; +} + +.recording_item div.recording_time { + width: 5.75em; +} + +.recording_item div.recording_name { + font-weight: bold; + cursor: pointer; +} + +.recording_item div.recording_name span { + font-weight: normal; + cursor: pointer; +} + +.recording_item div.recording_arch { + float: right; + padding-top: 0.5ex; + padding-left: 0.5em; + padding-right: 0.5em; +} + +.recording_item div.recording_actions { + float: right; + padding-right: 3em; +} + +/* + ############################## + # Remote Control Keypad + ############################## +*/ + +div.screenshot { + background-image: url(../img/tv.jpg); + background-repeat: no-repeat; + height: 240px; + width: 320px; + float: left; + padding: 20px 20px 98px 21px; + margin-right: 20px; +} + +/* + ############################## + # Dotted Frame + ############################## +*/ + +div.dotted { + border: 1px dotted #bbbbbb; + padding: 3px; + margin: 2px; + float: left; + background-color: #f3f3f3; +} + + +/* + ############################## + # Error widget + ############################## +*/ + +table.error { + border: 1px solid #E9360D; + margin: 2px; + padding: 0px; +} + +table.error tr td.message { + padding: 5px; +} + +table.error tr td.title { + background: #E9360D; + color: white; + font-weight: bold; + margin: 0; + padding: 3px 3px 3px 10px; +} + +table.error td.border { + padding: 0; + margin: 0; + width: 1px; +} + + +/* + ############################## + # Edit Tables + ############################## +*/ + +table.edit { + margin-top: 10px; +} + +table.edit tr td.head { + background: white; + color: white; + font-weight: bold; + margin: 0; + padding: 0; + border:none; +} + +table.edit tr td { + vertical-align: top; + padding: 6px 7px 6px 3px; + vertical-align: middle; + background: url(../img/bg_line.png) bottom repeat-x; + border-bottom: 1px solid #DA8DA8; +} + +table.edit tr td.label { + font-weight: bold; + vertical-align: top; +} + +table.edit tr.active { + background: #DEE6EE; +} + +table.edit td.blank { + background: none; + border: none; +} + +table.dependent { + background-color: #DEE6EE; + margin-top: 10px; +} + +table.dependent tr td { + background: none; + vertical-align: middle; +} + +table.dependent tr td.title { + background: none; + vertical-align: top; +} + + +div.dependent { + background-color: #DEE6EE; + margin-top: 10px; + padding: 6px 7px 6px 3px; +} + +/* + ############################## + # Search results + ############################## +*/ + +table.searchresults { + margin: 10px 0 0 0; + padding: 0; +} + +table.searchresults tr td.head { + background: #963B5F; + color: white; + font-weight: bold; + margin: 0; + padding: 3px; +} + +table.searchresults tr td { + vertical-align: top; + padding: 3px 7px 7px 3px; + background: url(../img/bg_line.png) bottom repeat-x; + border-bottom: 1px solid #DA8DA8; +} + +table.searchresults tr td.day { + vertical-align: top; + padding: 0; + margin: 0; + border:none; +} + +table.searchresults td.border { + padding: 0; + margin: 0; + width: 1px; +} + +table.searchresults div.more { + margin: 0px; + font-weight: bold; + cursor: pointer; +} + +table.searchresults a { + text-decoration: none; + color: black; + font-weight: bold; +} +/* + ############################## + # Login + ############################## +*/ + +table.login { + margin: 0 auto; +} + +table.login tr td { + padding: 3px 5px; + text-align: right; +} + +/* ############################## + # About box + ############################## +*/ + +div.about_box { + border: none; +} + +div.about_box a { + text-decoration: none; + color: black; + font-weight: bold; +} + +div#aboutBox_tip { + width: 45%; +} + +.about_box div.about_description { +} + +.about_box div.about_content { + padding: 0; + margin: 0; + + border-left: 1px solid #000000; + border-right: 1px solid #000000; + border-bottom: 1px solid #000000; +} + +.about_box div.about_content div { + background-color: white; + padding-bottom: 6px; +} + +.about_box div.boxheader div div a { +} + +.about_box div.about_content div.about_left { + text-align: right; + float: left; + width: 175px; +} + +.about_box div.about_content div.about_right { + padding-left: 200px; +} + +.about_box div.about_content div.about_line { + padding-left: 10px; +} + +.about_box div.about_content div.about_head { + font-weight: bold; + margin-top: 0px; + padding-top: 6px; + margin-bottom: 6px; + background: #FFFFFF url(../img/bg_line.png) top repeat-x; +} + +.about_box div.about_content div.about_head div { + padding-bottom: 6px; + background: #FFFFFF url(../img/bg_line_top.png) bottom repeat-x; +} + +.about_box div.about_content div.about_head div div { + padding: 2px 0px 2px 10px; + background: #FFE9FA; + border-top: 1px solid #DA8DA8; + border-bottom: 1px solid #DA8DA8; +} diff --git a/themes/redwine/img/bg_box_h.png b/themes/redwine/img/bg_box_h.png Binary files differnew file mode 100644 index 0000000..7763272 --- /dev/null +++ b/themes/redwine/img/bg_box_h.png diff --git a/themes/redwine/img/bg_box_l.png b/themes/redwine/img/bg_box_l.png Binary files differnew file mode 100644 index 0000000..e3d7dd8 --- /dev/null +++ b/themes/redwine/img/bg_box_l.png diff --git a/themes/redwine/img/bg_box_r.png b/themes/redwine/img/bg_box_r.png Binary files differnew file mode 100644 index 0000000..e1c72d5 --- /dev/null +++ b/themes/redwine/img/bg_box_r.png diff --git a/themes/redwine/img/bg_header_h.png b/themes/redwine/img/bg_header_h.png Binary files differnew file mode 100644 index 0000000..aaf8d6d --- /dev/null +++ b/themes/redwine/img/bg_header_h.png diff --git a/themes/redwine/img/bg_header_l.png b/themes/redwine/img/bg_header_l.png Binary files differnew file mode 100644 index 0000000..e49a7e9 --- /dev/null +++ b/themes/redwine/img/bg_header_l.png diff --git a/themes/redwine/img/bg_header_r.png b/themes/redwine/img/bg_header_r.png Binary files differnew file mode 100644 index 0000000..f121aa8 --- /dev/null +++ b/themes/redwine/img/bg_header_r.png diff --git a/themes/redwine/img/bg_line.png b/themes/redwine/img/bg_line.png Binary files differnew file mode 100644 index 0000000..50e358e --- /dev/null +++ b/themes/redwine/img/bg_line.png diff --git a/themes/redwine/img/bg_line_top.png b/themes/redwine/img/bg_line_top.png Binary files differnew file mode 100644 index 0000000..59f2ec0 --- /dev/null +++ b/themes/redwine/img/bg_line_top.png diff --git a/themes/redwine/img/bg_tools.png b/themes/redwine/img/bg_tools.png Binary files differnew file mode 100644 index 0000000..1457e1d --- /dev/null +++ b/themes/redwine/img/bg_tools.png diff --git a/themes/redwine/img/menu_line_bg.png b/themes/redwine/img/menu_line_bg.png Binary files differnew file mode 100644 index 0000000..a942e6f --- /dev/null +++ b/themes/redwine/img/menu_line_bg.png diff --git a/themes/redwine/img/zap.png b/themes/redwine/img/zap.png Binary files differnew file mode 100644 index 0000000..d5d8628 --- /dev/null +++ b/themes/redwine/img/zap.png diff --git a/tntconfig.cpp b/tntconfig.cpp index 6a6e576..e417de4 100644 --- a/tntconfig.cpp +++ b/tntconfig.cpp @@ -35,7 +35,18 @@ void TntConfig::WriteConfig() // XXX modularize file << "MapUrl ^/$ login@" << endl; - file << "MapUrl /css.*/(.+) content@ css/$1 text/css" << endl; + file << "MapUrl ^/themes/([^/]*)/css.*/(.+\\.css) content@ themes/$1/css/$2 text/css" << endl; + + // the following rules provide a search scheme for images. The first + // rule where a image is found, terminates the search. + // 1. /themes/<theme>/img/<imgname>.<ext> + // 2. /dist/img/<imgname>.<ext> + // 3. <imgname>.<ext> (builtin images) + file << "MapUrl ^/themes/([^/]*)/img.*/(.+)\\.(.+) content@ themes/$1/img/$2.$3 image/$3" << endl; + file << "MapUrl ^/themes/([^/]*)/img.*/(.+)\\.(.+) content@ dist/img/$2.$3 image/$3" << endl; + file << "MapUrl ^/themes/([^/]*)/img.*/(.+)\\.(.+) $2@" << endl; + + file << "MapUrl ^/css.*/(.+) content@ css/$1 text/css" << endl; file << "MapUrl /([^/]+/.+) content@ $1" << endl; file << "MapUrl /([^.]+)(\\..+)? $1@" << endl; file << "PropertyFile " << m_propertiesPath << endl; |