From 3aaa9c30d9853f47cee8ecbb23bca91f81bf9ab2 Mon Sep 17 00:00:00 2001 From: redblue-pkt Date: Fri, 19 Jun 2020 23:56:12 +0200 Subject: [PATCH] update glcd Origin commit data ------------------ Branch: ni/coolstream Commit: https://github.com/neutrino-images/ni-neutrino/commit/0c2dcc9eb16ec8fa00611fea765965304a14f1ad Author: redblue-pkt Date: 2020-06-19 (Fri, 19 Jun 2020) ------------------ No further description and justification available within origin commit message! ------------------ This commit was generated by Migit --- acinclude.m4 | 7 + configure.ac | 4 + data/Makefile.am | 10 +- data/fonts/Makefile.am | 6 + data/fonts/lcd.ttf | Bin 0 -> 38260 bytes data/fonts/led.ttf | Bin 0 -> 29836 bytes data/icons/Makefile.am | 5 + data/icons/oled/Makefile.am | 14 + data/icons/oled/advanced.png | Bin 0 -> 615836 bytes data/icons/oled/blank.png | Bin 0 -> 461965 bytes data/icons/oled/clock/Makefile.am | 17 + data/icons/oled/clock/analog_clock.png | Bin 0 -> 23426 bytes data/icons/oled/clock/analog_hour.png | Bin 0 -> 2227 bytes data/icons/oled/clock/analog_min.png | Bin 0 -> 1462 bytes data/icons/oled/clock/time_dots.png | Bin 0 -> 478 bytes data/icons/oled/clock/time_eight.png | Bin 0 -> 6486 bytes data/icons/oled/clock/time_five.png | Bin 0 -> 5813 bytes data/icons/oled/clock/time_four.png | Bin 0 -> 4944 bytes data/icons/oled/clock/time_nine.png | Bin 0 -> 6586 bytes data/icons/oled/clock/time_one.png | Bin 0 -> 3331 bytes data/icons/oled/clock/time_seven.png | Bin 0 -> 4393 bytes data/icons/oled/clock/time_six.png | Bin 0 -> 6479 bytes data/icons/oled/clock/time_three.png | Bin 0 -> 6226 bytes data/icons/oled/clock/time_two.png | Bin 0 -> 5374 bytes data/icons/oled/clock/time_zero.png | Bin 0 -> 6248 bytes data/icons/oled/easy.png | Bin 0 -> 615836 bytes data/icons/oled/medium.png | Bin 0 -> 615836 bytes data/icons/oled/simple.png | Bin 0 -> 615836 bytes data/icons/oled/standby.png | Bin 0 -> 615836 bytes data/icons/oled/weather.png | Bin 0 -> 461965 bytes data/icons/oled/weather/Makefile.am | 15 + data/icons/oled/weather/clear-day.png | Bin 0 -> 1884 bytes data/icons/oled/weather/clear-night.png | Bin 0 -> 1833 bytes data/icons/oled/weather/cloudy.png | Bin 0 -> 1255 bytes data/icons/oled/weather/fog.png | Bin 0 -> 3004 bytes data/icons/oled/weather/hail.png | Bin 0 -> 1474 bytes data/icons/oled/weather/partly-cloudy-day.png | Bin 0 -> 2610 bytes .../oled/weather/partly-cloudy-night.png | Bin 0 -> 2105 bytes data/icons/oled/weather/rain.png | Bin 0 -> 1169 bytes data/icons/oled/weather/sleet.png | Bin 0 -> 2983 bytes data/icons/oled/weather/snow.png | Bin 0 -> 4151 bytes data/icons/oled/weather/thunderstorm.png | Bin 0 -> 2616 bytes data/icons/oled/weather/wind.png | Bin 0 -> 2691 bytes data/locale/deutsch.locale | 69 +- data/locale/english.locale | 2 - data/othemes/Makefile.am | 9 + data/othemes/advanced.otheme | 72 + data/othemes/default.otheme | 72 + data/othemes/easy.otheme | 72 + data/othemes/medium.otheme | 72 + data/othemes/simple.otheme | 72 + data/othemes/weather.otheme | 72 + data/y-web/Makefile.am | 2 + data/y-web/Y_Baselib.js | 5 + data/y-web/Y_Boxcontrol_Menue.yhtm | 13 + data/y-web/Y_Settings_Menue.yhtm | 15 + data/y-web/Y_Settings_glcd.yhtm | 128 ++ data/y-web/Y_Tools_Glcd_Screenshot.yhtm | 98 + src/driver/Makefile.am | 8 +- src/driver/analogclock.cpp | 179 ++ src/driver/analogclock.h | 35 + src/driver/digitalclock.cpp | 164 ++ src/driver/digitalclock.h | 38 + src/driver/display.h | 2 +- src/driver/fb_generic.cpp | 9 + src/driver/fb_generic.h | 2 +- src/driver/glcd.cpp | 1727 +++++++++++++++++ src/driver/{nglcd.h => glcd.h} | 123 +- src/driver/lcdclock.cpp | 74 + src/driver/lcdclock.h | 34 + src/driver/ledclock.cpp | 74 + src/driver/ledclock.h | 34 + src/driver/nglcd.cpp | 983 ---------- src/driver/record.cpp | 17 +- src/driver/simpleclock.cpp | 74 + src/driver/simpleclock.h | 34 + src/driver/volume.cpp | 4 +- src/driver/weather.cpp | 270 +++ src/driver/weather.h | 39 + src/gui/Makefile.am | 3 +- src/gui/audiomute.cpp | 6 + src/gui/audioplayer.cpp | 89 + src/gui/audioplayer.h | 10 + src/gui/bouquetlist.cpp | 4 +- src/gui/cec_setup.cpp | 71 +- src/gui/cec_setup.h | 4 + src/gui/channellist.cpp | 4 +- src/gui/glcdsetup.cpp | 399 +++- src/gui/glcdsetup.h | 12 +- src/gui/glcdthemes.cpp | 474 +++++ src/gui/glcdthemes.h | 66 + src/gui/infoviewer.cpp | 12 + src/gui/infoviewer_bb.cpp | 22 +- src/gui/miscsettings_menu.cpp | 34 +- src/gui/miscsettings_menu.h | 4 + src/gui/movieplayer.cpp | 174 +- src/gui/movieplayer.h | 10 + src/gui/pictureviewer.cpp | 29 + src/gui/pictureviewer.h | 5 + src/gui/scan.cpp | 13 + src/gui/upnpbrowser.cpp | 10 + src/gui/vfd_setup.cpp | 2 - src/gui/weather.cpp | 12 +- src/gui/weather.h | 13 + src/gui/weather_deutschland_locations.h | 319 +++ src/gui/weather_locations.h | 295 +-- src/gui/weather_norway_locations.h | 334 ++++ src/gui/widget/keyboard_input.cpp | 7 + src/gui/widget/menue.cpp | 8 +- src/gui/widget/stringinput.cpp | 6 + src/gui/widget/stringinput_ext.cpp | 13 + src/neutrino.cpp | 125 +- src/nhttpd/tuxboxapi/controlapi.cpp | 21 + src/nhttpd/tuxboxapi/controlapi.h | 1 + src/system/locals.h | 59 +- src/system/locals_intern.h | 59 +- src/system/settings.h | 123 +- src/timerd/timermanager.cpp | 19 + 118 files changed, 6113 insertions(+), 1533 deletions(-) create mode 100644 data/fonts/lcd.ttf create mode 100644 data/fonts/led.ttf create mode 100644 data/icons/oled/Makefile.am create mode 100644 data/icons/oled/advanced.png create mode 100644 data/icons/oled/blank.png create mode 100644 data/icons/oled/clock/Makefile.am create mode 100644 data/icons/oled/clock/analog_clock.png create mode 100644 data/icons/oled/clock/analog_hour.png create mode 100644 data/icons/oled/clock/analog_min.png create mode 100644 data/icons/oled/clock/time_dots.png create mode 100644 data/icons/oled/clock/time_eight.png create mode 100644 data/icons/oled/clock/time_five.png create mode 100644 data/icons/oled/clock/time_four.png create mode 100644 data/icons/oled/clock/time_nine.png create mode 100644 data/icons/oled/clock/time_one.png create mode 100644 data/icons/oled/clock/time_seven.png create mode 100644 data/icons/oled/clock/time_six.png create mode 100644 data/icons/oled/clock/time_three.png create mode 100644 data/icons/oled/clock/time_two.png create mode 100644 data/icons/oled/clock/time_zero.png create mode 100644 data/icons/oled/easy.png create mode 100644 data/icons/oled/medium.png create mode 100644 data/icons/oled/simple.png create mode 100644 data/icons/oled/standby.png create mode 100644 data/icons/oled/weather.png create mode 100644 data/icons/oled/weather/Makefile.am create mode 100644 data/icons/oled/weather/clear-day.png create mode 100644 data/icons/oled/weather/clear-night.png create mode 100644 data/icons/oled/weather/cloudy.png create mode 100644 data/icons/oled/weather/fog.png create mode 100644 data/icons/oled/weather/hail.png create mode 100644 data/icons/oled/weather/partly-cloudy-day.png create mode 100644 data/icons/oled/weather/partly-cloudy-night.png create mode 100644 data/icons/oled/weather/rain.png create mode 100644 data/icons/oled/weather/sleet.png create mode 100644 data/icons/oled/weather/snow.png create mode 100644 data/icons/oled/weather/thunderstorm.png create mode 100644 data/icons/oled/weather/wind.png create mode 100644 data/othemes/Makefile.am create mode 100644 data/othemes/advanced.otheme create mode 100644 data/othemes/default.otheme create mode 100644 data/othemes/easy.otheme create mode 100644 data/othemes/medium.otheme create mode 100644 data/othemes/simple.otheme create mode 100644 data/othemes/weather.otheme create mode 100644 data/y-web/Y_Settings_glcd.yhtm create mode 100644 data/y-web/Y_Tools_Glcd_Screenshot.yhtm create mode 100644 src/driver/analogclock.cpp create mode 100644 src/driver/analogclock.h create mode 100644 src/driver/digitalclock.cpp create mode 100644 src/driver/digitalclock.h create mode 100644 src/driver/glcd.cpp rename src/driver/{nglcd.h => glcd.h} (57%) create mode 100644 src/driver/lcdclock.cpp create mode 100644 src/driver/lcdclock.h create mode 100644 src/driver/ledclock.cpp create mode 100644 src/driver/ledclock.h delete mode 100644 src/driver/nglcd.cpp create mode 100644 src/driver/simpleclock.cpp create mode 100644 src/driver/simpleclock.h create mode 100644 src/driver/weather.cpp create mode 100644 src/driver/weather.h create mode 100644 src/gui/glcdthemes.cpp create mode 100644 src/gui/glcdthemes.h create mode 100644 src/gui/weather_deutschland_locations.h create mode 100644 src/gui/weather_norway_locations.h diff --git a/acinclude.m4 b/acinclude.m4 index d72eb52d7..20531ce97 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -139,6 +139,13 @@ AC_ARG_WITH(default-theme, [default_theme=""]) AC_DEFINE_UNQUOTED([DEFAULT_THEME], ["$default_theme"], [Default theme for gui]) +# default oled theme +AC_ARG_WITH(default-oled-theme, + AS_HELP_STRING([--with-default-oled-theme=THEMENAME], [Default theme for oled. Default it is empty for internal fallback to default colors.]), + [default_oled_theme="$withval"], + [default_oled_theme=""]) +AC_DEFINE_UNQUOTED([DEFAULT_OLED_THEME], ["$default_oled_theme"], [Default theme for oled.]) + AC_MSG_CHECKING(target) if test "$TARGET" = "native"; then diff --git a/configure.ac b/configure.ac index 9c5a96889..601a57e95 100644 --- a/configure.ac +++ b/configure.ac @@ -371,6 +371,9 @@ data/icons/headers/Makefile data/icons/hints/Makefile data/icons/locale/Makefile data/icons/movieplayer/Makefile +data/icons/oled/Makefile +data/icons/oled/clock/Makefile +data/icons/oled/weather/Makefile data/icons/radar/Makefile data/icons/slider/Makefile data/icons/status/Makefile @@ -390,6 +393,7 @@ data/lcd/clock/Makefile data/lcd/icons/Makefile data/license/Makefile data/locale/Makefile +data/othemes/Makefile data/pictures/Makefile data/pictures/backgrounds/Makefile data/pictures/screensaver/Makefile diff --git a/data/Makefile.am b/data/Makefile.am index 7225b4509..36fe57242 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -17,6 +17,12 @@ SUBDIRS = \ y-web \ zapit -if BOXTYPE_TRIPLE -SUBDIRS += lcd +if ENABLE_GRAPHLCD +SUBDIRS += \ + othemes +endif + +if BOXTYPE_TRIPLE +SUBDIRS += \ + lcd endif diff --git a/data/fonts/Makefile.am b/data/fonts/Makefile.am index 0d5d077dd..a861fb915 100644 --- a/data/fonts/Makefile.am +++ b/data/fonts/Makefile.am @@ -18,6 +18,12 @@ install_DATA += \ ubuntumono-b-webfont.ttf \ ubuntumono-r-webfont.ttf +if ENABLE_GRAPHLCD +install_DATA += \ + led.ttf \ + lcd.ttf +endif + install-data-hook: cd $(DESTDIR)$(FONTDIR); \ mv $(neutrino_ttf) neutrino.ttf; \ diff --git a/data/fonts/lcd.ttf b/data/fonts/lcd.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1d0a4011a201758c8105e9525086feda07493cc4 GIT binary patch literal 38260 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 literal 0 HcmV?d00001 diff --git a/data/fonts/led.ttf b/data/fonts/led.ttf new file mode 100644 index 0000000000000000000000000000000000000000..81775ee5b43d0ba3f97f1dd950c01bf4dd17aff7 GIT binary patch literal 29836 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 u%ZJ}KrtN<|aPM7TsX}#BQ3-(`9BsSu%w?sx(yq literal 0 HcmV?d00001 diff --git a/data/icons/oled/blank.png b/data/icons/oled/blank.png new file mode 100644 index 0000000000000000000000000000000000000000..e85c206c820d006ec5cce7f1c93ac4500bc4d80e GIT binary patch literal 461965 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 literal 0 HcmV?d00001 diff --git a/data/icons/oled/clock/Makefile.am b/data/icons/oled/clock/Makefile.am new file mode 100644 index 000000000..f128b4dd8 --- /dev/null +++ b/data/icons/oled/clock/Makefile.am @@ -0,0 +1,17 @@ +installdir = $(ICONSDIR)/oled/clock + +install_DATA = \ + analog_clock.png \ + analog_hour.png \ + analog_min.png \ + time_dots.png \ + time_eight.png \ + time_five.png \ + time_four.png \ + time_nine.png \ + time_one.png \ + time_seven.png \ + time_six.png \ + time_three.png \ + time_two.png \ + time_zero.png diff --git a/data/icons/oled/clock/analog_clock.png b/data/icons/oled/clock/analog_clock.png new file mode 100644 index 0000000000000000000000000000000000000000..ce2526a4b41d42af9dbab183e6dfa8d8c3d333ab GIT binary patch literal 23426 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 z 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 B2W9{O literal 0 HcmV?d00001 diff --git a/data/icons/oled/clock/analog_min.png b/data/icons/oled/clock/analog_min.png new file mode 100644 index 0000000000000000000000000000000000000000..cbfa92024d1549b89181ec2230022d3aa12bfce0 GIT binary patch literal 1462 zcmZ{kdpHw%7{`BOn{6(+4Y4ESG9jaK+EAk{bH);4?9h_SQWYQJY|FT7nUn2yNP{uUqNuD<NJa;k~k+23$EtPn^S{t zB6AXa#~`+muWYq-?2VYye{J;06f4jX`WEVyc{x-8nU6i#p~}gx;YAZ?hKDtT0HXp+ zHN?TDCPix9b$yWTiXidGw%6fG&tL&?ENt^9L0tdJX=QT0p0w_{gQGNOOArE+**H|P zi@DG|PvOTu=xA^ zxiQx117Gzk>eG%Ll zN}V{X@bSvrZjh}Y+GkXPez*?ykw)^i^ZNUa4pu|+W3cOj={syj#;{q@Z>5XUfojRq zvu}berUXLg?hX&*IdSoAM&PZ zfuhsEz}3IK#xDPS73q`gG@P-di6D?A_qh{(rk4>qO8#@_6%)n}*EB1=97>4u#9-Wbp$QcxVZ%9 z;>Gg{weiX81-9rNa6i%PG>HpVPYFtvWZ70pFI(V86*s_zMFuUJO>_45U+mIE~@kpAwK>_7YEDSN6xuJp7E(Cj)kt0EI4kx;Tb-98XS=U|pOblEAp8 z=+`eJof}Ur<~*BkZ+>`|=xmwIN6+Qg|Eq~xe!9bT(&~qA@8945-%kJW5v7yX@2|fH za%$!uYj&Nq`~PS81?S4o#@x6gRq^uueEWJoi{#Sv1?MK3um7g2OC7#SE^>KYj98XAQdnp&BdTN#*X8yH#{7}Rmgx}#{w t%}>cps|0DV&^0jCH8Kb>FaW9pB5eaBAo=NrNGnhSgQu&X%Q~loCIDZkt!n@P literal 0 HcmV?d00001 diff --git a/data/icons/oled/clock/time_eight.png b/data/icons/oled/clock/time_eight.png new file mode 100644 index 0000000000000000000000000000000000000000..7efc32595be00a29a2283723cecaa2f76f13b240 GIT binary patch literal 6486 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 O0000L8{B-&N000McNliru;sF>9 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 literal 0 HcmV?d00001 diff --git a/data/icons/oled/clock/time_one.png b/data/icons/oled/clock/time_one.png new file mode 100644 index 0000000000000000000000000000000000000000..f117573656390645627f981cb984ce563c5bbd70 GIT binary patch literal 3331 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 N002ovPDHLkV1lGiNM!&3 literal 0 HcmV?d00001 diff --git a/data/icons/oled/clock/time_seven.png b/data/icons/oled/clock/time_seven.png new file mode 100644 index 0000000000000000000000000000000000000000..34836d00be7647b2976ea268f005cd02cb32f8c7 GIT binary patch literal 4393 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 literal 0 HcmV?d00001 diff --git a/data/icons/oled/clock/time_three.png b/data/icons/oled/clock/time_three.png new file mode 100644 index 0000000000000000000000000000000000000000..916d13dd23fddd0a5a817ad9dbdda9f5d837cbdf GIT binary patch literal 6226 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 wX=ZrL8{B-&N000McNliru;sF>9 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

}nWrq21Z=dBoDxzZ`C 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 z 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 IU-_N?4{a+w@c;k- literal 0 HcmV?d00001 diff --git a/data/icons/oled/medium.png b/data/icons/oled/medium.png new file mode 100644 index 0000000000000000000000000000000000000000..27827e97e526d02e24bece54d0453072905c431b GIT binary patch literal 615836 zcmeI*36LDseaG=PJF~mm)wPn)v5StCgd}t!Bw-LBAqmOG0)vP{oWr=vDjVaH_>VJDEXB?z(sBkRI4=s=)bNJ6((_iFF-|1EEsneCbF zneCpwzD+GN)5q)ApZBJJ(>-ssfBWbo4-Buat5!-4U-QA$A66=H#QIq=q{5o>dt3hd zOV&fhCmwoWwd#@o{%zwA{=u44_301(_Ma&=bd3BY)VIGg!J1k5xit^Jzw%hwgyHq| zV?X+Z?<-ZW)~sIn*cTG2xv`-sVXe|*{V*Yb00IagfItZa%1XE|c7*@}2q1s}0`CeC zz;p!!5I_I{1bh%6fPFw`mk1z$00IaQz%lFt-D`KvHe&%|c=#ML0tg@wI03>qa7{vm z5I_I{1mYk-0LP(~IYtB!KmdWj38V&7qaj0vsF5Q_sEUg6oWIwUPzlx9)v3;&Ij1^1 zJ5?%`QlmzXQbQ^$a&MDJs4JJRsO#5T)!4B&sj{*}?scv5J32emnbT)gd3m`SH*T!z z?&-1icUHBxxA!}|ku@V#jaBEX*RHFCwV&$hD!s3kmWwKxOzOH-4XMn#zZ*AhsIzC! z>9U6o9jXnI$+Dc=$bxg{&Z!$W+WOUp83-VN00Qw8C^~>gj2N!&U3!liJ!Z5@C36>3 zW(CvLt5?os_uv&WGy{fXZ(u!I6_2vFk zx3d20>Q>vfZdXSRA5rt>&sF0mj8{8;`75>a^<5bo$Ond{%kI@7`-`9dLQScktfo$z zs`l*Oqqc6@Zq;p}RksldXZq>mpvrk;OpqmnRRzG9iGsj1OnZo83H?e6Yw z^}_QT)yb2mGU~$%1WGNiWa}S{Q}6z}0HxkH`$GVM+yc2%H1{@oi3Hw++VSdQ%O&;J zTl-W`Pq#I{e_+a-_KptK+ImBW*R<(Vt!*xG%GI-6txEXGmFJPehx?V^ zV_o&u-CU=pPMxB!n)mNJpaXd2*fDC(+}Y~Hi4*GlxeI;!nSa|nHDSUytG)-+kt0Xd z)amtlAKl$Os%BJ;x@E>K>f*&qI@I-%So_bOq)u0^T+y?qOqs04j2WZ$?tN2TywIW& zW&Q8&O9@iX%huIB69NbzfB*tUpy&XWTgx(4TDNY84H)(Wqbb#>gke&z-eY*kf5tlQmPeF1mk z#5-!g6|i&X&r$Q|&r>hG_;VeAb#=9B)~z$u~f`BSy7>e4jZbEEqfcOvD_Y)+to}6AbW#6 zm)!0hF=B-6>JsR3JG!myz3*CgS+}xlYbRK@o2OW}n~$rvkG`#LU${VjU;OI!U#d%1 z2+MZ5w(nM1!o1Lbt+RIhvs~ud*3a6JK4$UaD%hTgxdfnKcs=BI5a;D$cp%S)oi+JI}+trwx#^?Z+Fg|tal=Xe@o?h?Fi&{NT-{!S$*;ZNQ z%9Z1>w~wjUt?zbwS2Y{-=wPe2Za*(vw9vY>JVD7VXqm2Gzpi%f+@-(!oo8JMj~_oy ze@A@m*l~4W|3SS@@BcDGv&Xs>J=Pk~HFw^e-awUu%9?cDtPc`LkG!p~tYxu$?|kOW z8GQwvwYsjeWb=iVmh45mMgRc>N+$68-~5eBO7;GYfRgQ$9XS>#I*er`^2+;{t6_30 z+PWI;AH}_OsJ3o9%T=R%&w9!Fkx|ICwY6&4uwi{+mR(yJLH*WS`_*Y{FjLCfPkURt zYO%g=wVO_zI<3nYZH>52m8Vo^NAGR&LkAD*{oFcxmL4%J``_{Euk;9QQ;vKvkZt5v zv|Op`y4_rB1^akwmCT?v+mu<`96NeUhw-UXXVmODv(?7dDH#keydFRAQ9quyVORny>Y}uw}&bUS2wwCXS?WVFsSzkFPj-RlCb+f9i ztLwcTZ?}OpPwLiT4N7A|009ILK)?vd{Z{*=F>COM00IagfB*un3ouOAby5mM009IL zK)``Ob7MnO2~zlDfBobz#sWBK4^}|{0R#|;sXz(BIHs~3HUbDBfB*t{1PI_fI4nW{ z0R#|0z$*a)*ehAeMF0T=5I`W000Eo_hed-G*s&$i%vgZIDzZHS2t;3iFphp3bA$*W zfB*sk6d-^D*eFy90R#|0Ao>CXaP-@lBSZiJ1P}|80i2VD1qdL300IbjCqMvu zXG_TlAbwXfOFEY009ILKp@Bh3pU^N>8OkaAdG|D)2JH)2q1t!WCaM|$Tlqp zh5!NxAP{5$0yxO6L){QS009IdD?k88wrM#q1Q0*~fj|p1H#Rhp!bLUFKRx-x@~Dgj zC<=g$5I_I{1Y8s#j9tW}C7kd3IPNVKmY-! z0tB#ADb_0Xwz+C~t*j-ObLjVB;5J13@00HcXiIosQ009ILa94l; zcGr{A5I_I{1Q2i}Kma>pVkHC+K;ZDj-~A890?-e<5g?4caivrQ5I_I{1o8?Hz9js+l$>17BYfB*sr z_#i+4`+&|a5kLR|1P~yA=>rHLfB*sr_#i+4`+&|a5kLR|1Q1ZojSWqtaKJmlryjq1 zhqq$^0uDg+5I_Kd7zhx?F=%8C5dj1cKp=Pm1aR=$gc>1$00IcaK!5;_K_hdB2q1s} z0>Kj?fP>d2)Cd7BFz(@Rbukuz&VWEX1PJ4Jv@=JE00Iag5HJA(IA9Gzbr3)R0R-Y9 zKmf<1ojFPb5I_KdfC&)50c#Mdg8%{uygK{Imlz8WuYN!n$E&?LS_BY40D*uA5WoRx z2&#bq0tg@wF98BLUhU1%B7gt_2n0lc01ik)Pz?kSKmdVw3D^bjPrvw;e`PE{y!ru0 zivR)$AmF2bT^RdV9d?ZX0tg_0Ks*Ep;CQq%M~MIe2p|wJ0RlK+4MKGgKmY**Vj|Go z*w91@$E2|bKFohVvFa0y1sK?gH4s1m0rv$6WA{xd5dj1cKmdUO1qk2)iC6&v1Q0*~ z0rv$6VE0Wa5dj1cKmdUO1qk2)iC6)Fs0&oDsrhxr0z|!)Ilf>E5XQl7A8LmH0tg@w zQ2_!tq7BPoA%Fk^2n1Vz01kHhP&)(=KmdV=3J|~%ZCDNq0R#{jSm0N`NStRZz`#!4 zuR$1lZ_FMLKmY**5a=gB0QVzd1_B5mfB*vC3lPBG8?y%l5I_I{1o{aO!2L*=fdB#s zAb^1P0{#YY_vHJ(#aICETbVr|fB*sr1X{q~Fb*^gl|ujl1Q0;LI{^aNJ6lRd009IL zKp>|80i2VD1qdL300IbjDA3&4&_oJ*2u#uT0_z_>d62OH_BPB#0D*W45XSLrca9nX z1Q0;LX8{7(=LTT+2q1s}0`U|efaBTj95n(6Ab^0+0tB$n4Z!XZh?79)eNBJQSb#XS zILGQ#fG~C{#d-)JfB*srxF|pXyNF3q2q1s}0th%2Ab_1pu^s{lAboV9#hN7y$$jKmdW<0t9ew8=`WuBY*$`2q2JKAT9yiy)aSFSb*I9fF%eZfB*tM3dALheI#br2q1s} z0toaMAb|UuFb4qy5I_I{&jkoz&xzRq0tg_000K4w&5aFBq_7PPv!WvKUr&7XlZ*w3 zN^5c)2t-+cFphHTa%>17fB*u46(E2E+cZ=R0R#|0Aj$#+aFkn@V?zJ|1P} zrlDd8AW*!((_bh%&RBrr{n)b90)%m?#n~SM2q1s}0+s*)OgBIP0R#|0zy|>W*aviW zi2wo!Ab0R+M$KmdoQt*9vi2q1t! zgaioS2sI{$f&c;tAP^n_0ysQvMNJVv009IdBtQVW-I%j(`_a(wjRkO9f$|VQ009IF z5Fm^Tz+zPd5I_I{1l$rJfZdX$90U+R009IF5FmgHz+zPd5I_I{1Y8qnZfs~Ggzo0t9eTY;1%80toa9eD>uTpJFTkyfun%DI01x;k{|kh*c> zMy}PE@1wx@@#B^B8)>Utlj#rAXVUvg_WIJ#WIBHQxH^6Mw0@qie7p7aM*I%}j|2!{ zk6>5^nqo|mZ^c-QTmJgr1z7~&d!V@FoF8|>#ys+BOlgG`SRS!`nmd2#*TOq zTY*XEkAKpwu>gc|Y`c;72flOXPPKpk{=OZJ88b#b_~3*3YIM`4O?~s_geNCo31&Hg z%8xw1eEG8a$xnWw&YwT8uaZ}+SfQ_MzW2TF>1~%TU8=8))7M|We!ULvzQWU<$a-=D zmVGe=Q^2&l({`+^tjy>qc1N{n(IWN8BabL4Q>OHOm23UAYuEPmJ-c<7hkzRb1h5;5 zlwm6%SG?w`S5}bQh!TKuOIWUAvnL5ibK6>$$+|5qEqYzKl9gN0Cr_U2+g7e<%=!}I z)z#JNeeZi;#y->cA!SH;+qP}fC*kyEJP(FIcXzkrcHFvkt8V}FeqwhN(yyfNNc+p= zbba|Sz=VL80`xF1btyYTzapT6mD_+??eYsrS$d&c>?b`>u z1ua+3Ou-b8Aa&Y~vYxD;-Vf}KDtozH*~%5MTy5J;64-L5M6Q&X5b#of0QOSX+p@Rc z^)c%NQm@vmUip}}d-9-kImwwHyW-695T?a^jScvJXAzQYs=^GfB zt6b(IFjxWUalL1|!Is4K2n--FWXKRTWy%!&U95bsn?1>|rAUa%uN$TRs#30BB}!jE z-><2d{g^8)H-9}z$}BHWS>H9L`aUq26TVz+$!$=1?e!!dE~=`k^c9|5C5Cm%_v=IE zn8aM}Xk`CN+hF^N3E=c!XEOWb5dkj*2w*Q%DKpXna-vS9k~(zdxdd!iw-vPAJ^gNR znlSbfMCwppUaki+$rTj_if^1i+`{0>%U%7b?d3u@wmNrKZ%)Oy+}vdCemN2n17r01jrmP%8uw zKmdV=3*`Q%(IbA~93BD)Abr0@rJC300IaUC_n%g2*&Es7hptj^xK#tL?8$P z1aJ^qfjS_700IcaPQZBp|KP9cf0MBQvFjjlJYaJhTCRk-9UaFWz%e6GdI9HQT>84P zM+AHk;C8ex?CcbQ*a;B8v1@V;7y$$jKp+SL1aJ^qfjamqko|8!`&t=xjsOC&5g>qL z)6|1F&>!q;uVyU3AOPdFsoUS7r&1~F??mz!-s07Z;&-(4@c6YkM~r}L0_njk&)xVg z-Td{Zr2a$AN&UAO5u8pr3z*}dF%^d>9FPHNqyTVnJiby zWbZ8?`4pN;m8q0|U9M7PDW&I?zq>q{?E9Ol9v>gYBak5=Cu;foxN@@Y?C4Zoo!0Yi z>v?B~>gv~yF^T4usHt$3ay;Hp5O=OQ^rwYJ_+ zs=2YDsV{}CbCGqH>b5>|O3&}MdTxjH*!x$@6Y`iS)9(m*)UU0-W-jj#>EZNpR~wYV z916(UUVh{qAU{3b*7Kg;=klmu>t(XuyX#nw($|>=7Wn$#wEkUC#sWzDwYRtTRl4_F z)viBd{23){=n3VSc zQ?LYRn_#sEwQ*OVOzt)ah^D~T<}CP&po|5Grf~nG;$Q6O zZ^9e|5I_I{1UwheSHqs~g&iP(00IagfIx--SHKw@yg&c}1Q0-=Gy(*0X`I;$0tg_0 z00J2TK@8vv)yqG_Sb&UX;spW-Ab>!W1%epHQTFE85I_I{1Q5^y1TY-|0R#|000AEa z2w)%3*(Cx9AbUb^k{h3lO9hp)Lp@P!a*cxFpQ%1OWsPKmdVE0RlMF zgI5S3fB*srlth34E(tR`K>z^+5I`VHpt-T3i4@L4;UxkHlv?19Jx_d|u>hr3XMe#G zAdG|69@GW_1Q0+VCISR-Od6WQL;wK<5D1n40UWIMpf(5~fB*t95g>qL($E|x0tg@w zJb@p7=Er}^SO94k!Z>)nlNup_00IcaK!5;_K_hdB2q1s}0>Kj?fP>d2)Cd6t5I`UX z0t9dj8ks{x009IL2%bQ^19;va{qM_+1qfcRq(%rJfI!Ry;vL2@Yite|0R#|0AUFa9 zaB$j!njnAx0tm!NfB=qBV{@noAbu009ILK)^GB=EjC5QrI(I3Pu2d zpb1QS@&n&tEI`m&h5Cp9VN5?j009ILK)?q90@w$1c8LH22q1s}0Zbo2009ILK)?q9 z0@w$1c8LH22p~{efjggA`#_M#0uaWf?GNk?0R#|000AvP0Mii=KmY**5b!~O0QLc$ zT_S)00tg^L0MiE$KmY**5b!~O04@#sLq~T1EXZR4N~6GD5I_I{1Z)KeV_OzxB7gt_ z2q56C00Hc+FQp@Z00IagU@JfX+p;hd0R#|000D0W2w-o0DII~wHyqi;SOEF~0tn<4 zAdK_!un++R5I_I{Zv+TnZ(J!A0R#|00D-&$1aMv+79xNE0tg`Bkw9}}LlY_N5iZ3d zfIyrDYOj3lDaHcCxd#+_?1XWlVyuq<0tg_0fC~ZyunUM3fdB#sAb>!j0t9fOVyuq< z0tg_0fC~ZyunUM3fdB#sAb>!xz~^55$A2k&EC69l|3Lr&1Q0;L2LS@u2XuCc00Iag zfB*qZA3y*B1Q0;L2LS@u2XuCc00IagfB*p;wLUPm<>ftvj|GUD0>^^@0tkdkfG`eK zb5U6Y5I_Kds0a|iQE5qz0|5jOKp<2C1aPRDi^?K^00Ia^MSuW~N=tGa2>ht!oBzpJ z0Qvy}p%fsDL)mOp8UX|lKp^Y_1aR0}koqHl00IbvQh)#sWwTLf1Q0*~fzS&yH#Rhp z!l7?Q4gdiJ;w*5-Q(xM^Sb*^N0Kz!@ZO9QIfB*srgiwG04q>BFWdsmF0DVU7QlU1N<;vGzz7h=foTdVf&c;tAP^@30ys{s&9NeY00IaEMt}eg zOjA%11Q0*~fj9{ez;SAAjunBh34H#k7uGWtAZ)EheTxtvjEg{H69f=I009IBD?k7b zR*>xxKmY**5GX=`04@TJO%Ol;0R#{jv_NxXLlY@HXhsS^009ILa8uxqhks>S+{OYB z#%}f?%0d7E1Q0;Lp#TBw5Q^0hKmY**5O7m~0CrQ8vJgN30R#|mC_n%^gkm)W5I_I{ z1l$xzxmj2tWhD{`N2~Yr^kl4OwsSf^V`FD8KJwxFR>o~CfHN7^Dq6tw+kpx&{aV&H z&vR{)zD_aa=PFm`XYaev^7EC=G6d55lj&>e^YRH5yS|i}z7JDQzWMp;;r23L!g$1p z5$eu6?^L5lkIs8Mot>TPjW^yYz}L6 zW_upvEgatJ@b|c)@m0^2y|}#~#aAcIC~kt)2C0X z4I4J-AeU|Oz5isnoFL^#ru6rtc|OqgdPDw)fQ>+|zLRUd6k+;ZdU1uUfAQi)CGQyt zW4SfGeED)UWy%yK^W}Ya{P^+oqD%hV*D#h(M!6A@?|}#kCQ3i$<4|3tb;(I0_I$Ax1C)^6tcdoEAN?U)28X$ z&-L~7>fphHdMwfO>C@Hix8JVsLgjlO+11OfdA zkiJm9Kahbg62Nl8lG_M!B`kxx?!EV3y{ceK2s0tzr+@^W^zrl$kOS4Ht*uS%+O zvv~1hy}E2KgQ(;#Q2M9!Ld$oue!g|gdsfzALZDay)5pyAa(h_rY|2+Fc9Ud;ypPP} zbba%_lkb{M_{x>d28J`h90U+?sur;?b7?mV5MaZ(hD* zTDo+p?QsgAglsyB3|d*RV1d43*s^7d4q*AjF6)`^iRCJS2?4(aq~A)Q$_Grl+h|fh z30AqPmG6s9U*EWKqy9i?-WPK6F}JDZyE8L6EnjXyOZl?CoOI;9muoWLN!zU>^JIHj zhY5jV1xz24D^nTwApKqfINy6j`mpprr|Zl6#q?nr`7H0jv17;T@HJzGWQ4T5FJyq0 z8DmlGF%4!r`LZYT7jOqtn!|17q#^@M^8I>*6lKEI3{H{JZSo_Nxos!UWu6&TCk<-W zmt{-{_#q(uQARh*2TAj3+^!ySi%m`}>9^I=`?G8#%jCqBy^bm0u3R(EY%3=kdB4f~ zCcPZ9o;=Ea<-4-%eaSL;&&tV6PHYi2JF}7C`Kn>;=;MoAf(*o$tLOrAYsi z{#oey(&wcQ%N4Y|4`e{Eyzk`wm!3za{9Nx5`y+8@t}kKiPSq&|0R#|00DiS+x)VjIdJn>%H}gC9`jhreX}q31nf?he)K2z zj);={6tL@0cJ;|VZ_wxLl!86aw6)#822zTe`x3x%U=qM|*itkx`#=Bzw*}0JTgv4; z=C*F>%k!%ZeYpiqr!9R4V~+?R;GTeACv5kQfRchBzZ7Qjyh_Kg4n z2>31_w}bth2xC9>**5|RAb@~x0ww?VBD0Q^0L}v8B?1T_fB*ue5Fmg{q0BxIKmY** z5XcfBfU`h&i9ksNzVU6fi?IMDp=Kutgh9Z!Ur!1H4s}ET0R#|0z$*c+hP{%dTm%q6 z009K@2oS(|a9D%@0tg_0fL8(puvfB_ivR)$*a*7FGCST{chj{pJ) zAmEn(0qmDN`$Yf&1Q3X|00A89=I7uMKmY**{1Qlv_|&C;CWZatXTJy_fB*uq5m>dm z?u+@x0uaWr=?WYu0tg_0K#&9o;2^aIbwL0D1Q3Xg00A7ErshBqKmY**f+Roy2dOov z3jzorfIw^n2;g`$^_Q3Yx%F>?*Q+(FS3VYxBjzX(KmdUd2@u91YAmXX00Iag5FG&m zI67^~ksyEo0tkdifB+6rV^LKE5I_Kd=m-$N(P>ML1OYpN|7$-#nXv$NGR#9DKmvqu zfEt6UAbL1(nr4 literal 0 HcmV?d00001 diff --git a/data/icons/oled/simple.png b/data/icons/oled/simple.png new file mode 100644 index 0000000000000000000000000000000000000000..fa6d0fcfddb2cd3d3d4709dcfedc4c6f9555fb4e GIT binary patch literal 615836 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 H=WG8DXuN)K literal 0 HcmV?d00001 diff --git a/data/icons/oled/standby.png b/data/icons/oled/standby.png new file mode 100644 index 0000000000000000000000000000000000000000..12becb1ec6e532f11e3798f9394c70e112cef701 GIT binary patch literal 615836 zcmeI*Ym6mXT>$WVdwPcD<*GacKEMWI5Zy>Hib{O&SXd?kqqs3yTns@WL7+uNB|z+k z5TlVLHlh+kM2*H(d7BkPTmun>gdkB2p8yRI(S(N~d|+q0+k0;J>8ZY5RkxnEUcbiP zs#|r=|NPJI)bxMuoipQa{rIzPzW;q5cAwd7cK^#yzva_^Tt{nlTe&F=ev@I9aX;aeWExOlIZUw-CO@AbK@ zhdl71kGShuPyF<3cEjxQO;5Vz74zBt?#|wP(d20H?TY{b0t5&U*r34H2FEfK0RjXF z5Fl_Opa6Rm2oNAZfItTV3UCMLh9p3M009CD@C2WM!z=&(n79{Ug3~u;0t5*3PCzm4 z-I7R%009C7rXZjIPhpkKkpKY#1bQc+0QYW5Bt(D!0RmGHP=Kef%H~MmMBv6x+ z#%;-pOMn0Y0t9jd6yO{jw+Ij*K!8A70t#?jvf>gTK!5;&903J52gfY}1gZ*r<6FP; zUG@T0)zfc!0*dkU*4&H<5FkLH2LcLk4;DcR1PBlyFg*bUczSDY#smluAkYH=1-J)` zAO!*h2#iPI16x;q$X!}!*71N#o0RjXFG$5b=H-IPv0RjXF5GX640GAcho&W&? z1PC-Bpa3_3CjXS4eII z2;>PU#(6sK5g@GvC0Jnz5ZH{s z>p%FFx7iD@8Ed1oC!iR&XDc!R0t5&U$P`e3Gilr)K!5-N0__PX!0p+JOn?9Z0t7Mz z6yQu6HwX|QK%mb8kNubLf7w{}0w~6Pe$wPdfB*pkqZLqqN4vBpMt}eT0(}-xfcv~U zaw9;10D;j8D8Qp#S`#BcfB=DB3+(Ui?5V<)mgx6xf5DHAWiLP_0G$XBAV8o&0mZmM zOrZ!6AV7dXQ2_;CXEOX zAn@6*{_LOG3*b3uM?f)d$5m7U1PBlykSm}7=kmBofB*pk1lkc$fZK5ul>h+(1PJ5` zD8RWqZW16sfB=CjkA2Gf+uaMG7<Qwjca>yL$n84j?@O1PDw(Krx=cBAX%s0t5*3 zPe1|g-ur-2Op( z0jBjFD8|!TZ?h#pfB=D>2q?fkSqNzmAV7e?v;-93X|1=}5+Fc;Ku-h|;GQgmGzbtN zKww$|X$APMSHAA8_5w`nIWSuS1PBo5P#~=scbJZ$2@oJafWR~a6yRyBvsn@#K!8Bc z1Qg(&Er@go5FkKcA_DunJA10|L>7DfH2>raPkFw*0PCH!AV7dX^8$)-^QIyaAV7cs zfwck(@LD1b2oNAZfI#yC3UKqLA`&1#fB=ED0t)b2A`J+PUEn^KzxgNa1sMA(n_s^L z6ytuckL(B#AV6TG0t)a*7uK{05FkLH-vSD7zt=~01PBlyFj4^pc%%z!S_B9XSTFFe z|2+Say#VW-+Hav4w{L6&0t5&UAaG7V0X|3K0s#U92oPvrKml&w*a!p&5FkL{oPYv+ zj>H851PBly(7r&o1^DpcPkyt#0PU}`5eN_;zr|ktuw{evKfoTdT#?xGP zvnD`*0D+DL6yS~*!0-eJ5Fjv30R?!P>u%Nr2oNC9v48^H@d6m0z?1~;`H{WfwijSZ zD{ihu1r+0=QrZz9K!5;&1_c!01~G*qK!5-N0!0NB;G$C65gINQb@0t5&UAkdnC0^Ay{zyt^oAV45nKmpFSafbi_0t5)O zCZGVfMk_D@0t5&U$QGDN0X}@({04ggvY!KY2oNAZphJPF6ypww4NZUm0RjZh3n;+n zO0D&3BU(&TAwYltf#C=! zz{6Q9nGzsCfWU|Z6yT;8^U>e^j{6R8FF?}@;t?P~fItZW#kd5PrUVEOAV8og0R^}z zNpT1eAV7dX2>}JT1eT@*2oNAZpfQ2{-JLyExG_$FrY!L8?RVc{FTj+a0COi$Pe3uQ z=chLT0t5&Us3f2OS7OtN009C72-Fi$fb03`O@IIa0t6}vD8QB2bRs~2z_GwDedya? zWG{fHp{{^pTvt$k0t5&UAW%U-0j_|i3jqQI2oR_%pa9nu)SmzW0t5(D5Kw?Cpy@(@ z009C7KK6_+Kd`C20E)5ai2wlt1PF8>pa6G(Zb$+I2oNBk0DA@q5FkK+KnDT}a0lpy zBtU=w0Rjr}aG!zC-*xBbn%WC6Tm_jEAV6RQ0*dhn7SR+45FkKccmfLW@YYPm1PBly zFaiMucm#`R3IqrcATU6I{oS2CRd|34C*>&%yyrI`^+kIDru+n$`#1#@<8iL5SrH&W zfI!a$6yTmOkn{);AV6T80t)ar*VU{D5FkLH=K>0F&lgB~1PBl~7P$V7*L>DqfU!Oe zit$)i*1QN1AV8qk0t#@imq&602oNAJRsjWgtSf6?1PBly&}#t&xYx@gIRXR-5E!dK z@dEtf7am=2FThxz1M?z4fB=CG1&SBr4wE!A0RjXF5Ez?)0z9@AH6H>52oM;AfC4;- zWs)QT0t5(*O+W!2+lsa^pYM3dGoE8FKpV1R5+FceDWDj85C{+;K!8980t#>k=!PUf zfB*pk3b1E@009C72y`K^zq_-y-NnFNjX9ssyBd0M;~pIy4K8O1H!JX_`Hj!D7ob^F z(FkM-jIJ0b3vSwZycUlUCcF*>C|*y#j@Q$Uv40oGqB*W>m&`pD;c!fzhc@wbY`^+C zUUwuwfB=DPf$+XCyx$3L4=3@qCl=OKlC0~oU0(5uZ9*Z+YZvdw_EnBC#_BP~TD@NM zbz1*;EgVCf)vvT`t8Kg{K!5;&e1XXn;Cu#m2@oJafWT%2?8@4#x6ud?Akce(%m4Q5 zo9zYI>@q3FoAovt0RjXF5LgN*z#aqw1PBly(1Cyg+yS~F2@oJafPez*86ZG_009CW z2(z*u?9 z%#8p60t5)u5m12Z=;=#<009C7DhepT72$LvK!5-N0(Arw;5vHx5+Fc;Kn;OAfAP*= zuooZzD#kS)BV7p)AV7dXRRIOKs+@iV2oNAZpoV|~Tmw&60t5&UAW&660j?^i9{~ac z2oR_tFzo_-!Tqi()009Cm3MjxW;tEZG009C7vIG?1EE(4c5FkKcGy;!* z!Ihi)ycb|QO?p0`r(IrN%e$A^$qfPo2oNAJa)G0xqs$qm-3ygAyGLdyHwX|QK!5;& zIs(ggz~No(>URjbdM)jBox$}bK!5-N0z(!E?`+q7hxw(oSr*`}t@-TYrR~|p?Mt%@ zTNh^+E^g1Zw=c}LFKitjw=d2vURYe;-d=uRT;5-tU$`*a+B*It<+QigLq?T50RjXF z5J(dUZ$`t{;o;%z;NW0(&pr3du3o)ocCa{x@2dw_7uUk~;@-jG@^}#LA6}hZz31-P z)w>tx2S>BzN6?`FZ!L=L*8I4j&bKZs3i0A~xW4?pc5m5kd2j3V9dcTNuALFM?Yh_e zW1sf|oJrOT0t5&UC?^o#;fA8T{9Y8^eBL;INdEOGo8;_Owg2oNAZV5$PKPG;4Iei5Ey|#EWTByq5xM>(}zHDfp^~WsgK$VP~1yP0+ST*uVqbg*-e@N z0RjZN7Epk@UIF71AV7e?Bn1@UNiMrd6CglS{9XXXxU94G1PBlyK%fBu1-Jo3AqWs4K!8A50R_0MnDzt+5FkLH z0RaWL0Yo7P5FkK+Kv@9=xU5*;+dt?lANr5-dja}BEBO&1Kw#7Yit(tI*W?HgAV8q6 z0t#?nS4Lh02oNAJY5@g!)XQsf1PBly&{qKkxUVZCF9Kx+-tm<`_)B{M%BpEkpcev) zaW9rZ5(EekATTun1$b&JZoUKv5FpSC0R^}h%OD8?1PBnAoWTC>&Ymhfxn(zD0tCh+ z@V$4u>V5VC41Yxx2vG_=z0~5Pk_KE1Qg>@ETc&f zAV7e?&;%6Vp{ZYOuhuV7ub6Ay|35{(EU2d zU_=6n@rV}FR0t3tKwvlm3h;2&N~Qz|5Fjuj0R?zOi)ktZ2oNAJAc6heojp}}Kno^S z0t5(jC~)b@XY2)N%U>~WOIBP01PBlykRzY~=isG0RjXF6cA8=3m|DifB*pk1ez95fSVQ-uX%w_{Pic_ZZAOdt|Ag3&>I28xHn57 z5ds7V5SWsH0z9SFHdg`!2oUIvfCAi`rH}{#0t5(5Nk9Rf(rTM4fuRZf>Kz|=ue|_6 zTQ&Js5KxROpy@(@009C7>Ix{pbp`b&K!5-N0u=-l;0kEE5FkK+0D;;9`@1`Ps&H*a z0SFKvK%hy1m)!q#kDS_G0L8e;CrB&;1PBlyP*6YtE(oO=0RjXF5NJ|B0d7)LECK`w z5Fk)cV7p*D%?MN$n9t{x`|3!50D-mzj*gDn9wIfq0(_q3lMlOazrpPVP~^@pq$>mn z5EzPpkE4gOQt~7~fB=C}33xX=z~!9UJKwzd#*dL!+r;a2mUlH~GFB7ulkxJ#O18^8 zUw)vr_*iZE;eX`_Vv_f@ z?g!Gk{xNoplh;193HReM_KnB981Y_g8{@>+RgW>>wD?tH#(r7zjQ8sv+ln7elKEx% ztX@y{$vOY^$G!foxqAVMex+=Q#MxH?N{fT_PT5iX)%gk zYkRDr$4@%8J(sS=N{-vrd2b7F(;(p?s`HiigFnQr8^26$>vCC*m6cnF6Ygc*4{=t< z%4@qiZt`{2erY)*;}$uuI`-<^v&L#We%82Eu4m;M=Nj&>Ym+x_R^Pln@m?~AcpmS? zW1aXhM&5Dg@w4VuXI^nFLX3F6I!>MVtFfl^y3+!jy_jJM))&mI{&4}*9*WQ>e5c)u z{nj1x9>jGyt&1J+*Ud4;3CFZpG0$*}=gB_tJn0nA*Y$~g!!g+>y5)_R?3+A~apJLT zjIFI|TOZ>_Pq+tp)Q-_@W$ z<7dse>b&~0E?M&$^7YONaCjK9zK(BY-_Po|dOeJhe0akBIBq zf6?nPZfGCQWBk}Zc|Tq&b4-hw*FV`lo>$GGYQKLl`@6+?wI@mSHgW z@_c$XiSUDFv8E?qpLzeQUwLLPK$CL`vEs8E2W&EajM<0dSm)KYZD+-}?TM|%Py5BN z+NQ|srs8CcmGuL^jdAP5tkZY(hfbC0?1ln}{EOEv&|h*URLS);8Lv-OIYRnoCx@yz5QnpEpLlS7nZ| zZxhE(3vgGH?`qs43l<*W@SXSZX3_jZyYN-z7e!Zn^NeCn@mOVEdGX`DKEy9Nw~%Ym zwsC&p80VP0wtAjybNZffwNXc}levWy$~r`|)i_N}CmFwNZbfp)il4lm7AMX(wo7Z% z<+Yes{P`DOcbQY0V|QAB+niVzvHSM0)XArfzExu;e`vJv!)*0gsha0%oUGSP#?Sk6 z)2#8s^&&YGX|p;;l|C^>T<7>Y@0c}C*7XppNc_D1dHEE%S2y;${ENgd(k9NOt+p|K z-m%Qsd2xDwZ+~}ZuhS~rm2{iquKSfz{3)j1@KQaG;~r;T~GnM;w_Cx7(N$kd9AS7e|n zaguACHO9KQdH2i2&x@0l+q&y@W3J0TFMi&=b$J)LALGYkkv`hYW(sh_Pr#-s(W4~mok0Iv`w2! z(k<=&*sdwSJzLTE08i~f?AbC%hd?cXs()BtYtR-uho48A_?a{|w{=U>Spg1(W)lk< z0b*gRJ8o8-cs-8S#4+j9bo?p~F^5g}O%2-oB5*k(1icz^YJY+v-46(?RV8fRU* zrt(aV6P}|Gw~1WSVhkyM(j}fZnSYF#JhmM_Iacz#?Qz?VpPWmZ=V{M$o8u*8cUFLt zNo?XgJS-h8`epU`+ombX;hjcwus7|(og@e2%k@ zPwQ!RVXe;0H>R?UZ?lth0x~YJndeh zS>@A^+i~pnMu=-wImyBugVtgmOSBWY)Muh_z?FuJn5#dZmo1vNJAP(X<>JqUYuArw z9P&Du_F}%*vN?$o8pW?`H;=C@?uFl6#@}GZW}7;O)K*j4$k=WFu52TdFbDwx1PBaX zpsNC0?VqwAJhurDAV7csfo=s9;BNhmK2?Exf7_RTcs9FXcKN0!-7-}J^Cm#xRG_nu zqfaw%LVy4P0t6-~;N9>97u}Qz5FkLHdjSQw`!$dO0RjXFOi(}pp5UUJG64b|3cTm< zzVtix0(7_l{Tx~`?&rG5iU0uu1V%2P0FQiuO^*Np0tEUgpaA!CU1UXo009Cc7npz3 zi~jHTRpF7Zvgr{ZK!8B^0#Etm!(N%U7eF!YevM>6fB*pk6BJN@C%EXQOn?9Z0^JKJ zz}>Hb3@grffB*pk9SA7E9iSVM009C72q?gw0RjXF5FpTjfCAhBx*-V= zAg}>}C;!uxPt0cXKfip_lWy6-aE7QOaO)TU=hDwyzx9X^S|Zo zYH9ZcEA~xUwbH86zFJjURcWMcleS6|L9&IEBv|4hNg;@bgz#)ICfIA{i z?d|Qh2D4%|-Mo3z?8~lXw^P+=8g}K%74N=WyXGwd2p|x+KzSfFmX(z$2rgT;Y~{+8 zz7@8%wvLR9Y}&MG?%cUOJw2J`QT?5rodW{{SFc{Js;X*gYWn1pPrO01y1H7Mj*l;! zH*Y?1;)GU{?bHO{{rmS%*sy~K4|@0Idk9faym0VWk1-b@>SvMm$5bGgU_E>G>@8ci zD5Aac$}58M_NM##`V?dpbB`T6rugW>G;uRU9%axj)~{cG>eQ)o=gz5qrD$>PNOda3 z)I7d%Y+WnriTm!<MP2p~{MfnWl3d3pJ~dGqeO?>+@PZ|jGLht;dq z5QO@z_4W12?8;*TtHS7w8#jFOD1i3&_p6dimo90bWAEO*4?g&y`pbt79nxD<+w$eh zAAb1Z!-o%FxNyN)zk;}iO1iqboQckLwOM&mG)%qnlP6C)i?EIW0tgg9VC+lsa$nRB zJ#yrTD>9mDD=I2hty-mcn*LrCuNA~yi(<55w<^(~hsHY8FJ7@?#k6VDY_%E+U$SJ$ z*|TRmIy!73D+nNfKy(G%o!RV;L;?Dvk3LdJ^^Q4cXhP}AV1^yepFf{^h(nQAJ=Q&Y z_PAOyfByWImKKF(6MxkyR(D&&ChDG>oLael{kmy@*_TPzy2i>i4(_VZyj8=rqCBY^ z=3ACT1Q0+VuL8jY=vlL7H8(dahT3px8m(@x9`wEY?z?)>H*@ApMNf5mHJIRgNP4KK z5e#*cl}(E)k1Iu=2byT1QR$kR8ne@*M~}Y#`s)hZDmY%jSPfcHg}ysgP*w(gT3oz% zQ8oDHF>TNTLoH^VR|F71pkM-HK`QrU`t+^m|NFo0&IOphc=2M5Y?u)VTe)}ITskx1 zQcSILZkjrEYC}VVDl~CiGyLp8hie{QIy+5~hv|3rgtCGF0tg_000IagfB*srAbgx5dj1cKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_Kd zND0*cTj|S*M17*Usj($e4X3dPAb@w(Z!tJ?_WI@gaZ!0tg_000IagfB*srAbPMXF_;TbFfVq500IagfB*srAb@Vq+C}n79=x)0E;B`qP+vLv5dyhcb*y8#nGVVAJQ@j$){WA7C z{!c3@?yvG>$3A7sl-k<)Gp1MQmut(XC{~w`Urc4h=wxEiP1i5u>DN7Ul?>e(8rHuN zh2s%@9P5ZmOH01^;){-sYlDM>-UH-f@S0?lQe9m=ckUb&8UL;Iu@A+vQr&0e+;JH( zMkuqwvFk%oEA z-gjfS-gsA9w_BJSOxq$Upf4~o17gnBXA@kUvMQ&Z#0VBe}9W%JFWhb^6*ovp2{y}iAvaNW9fYL6M=(W?TtGT4BkHh7z1 z_rgkQ0WoTX!wjRja@r3_S9-Fy=8R-oDp_seOgCI99^Hqt*|aJQ0>K3688c=qU%p%y z;>C*>T}Nf^K;6vBvvTE1-Pqp9IBnXr6)RS#pdzg5QP(VWJ<6kc6wO`xGR?Sj>5^i! zb5mViokI473l|0k2At`vXD48K(0A_K@fO$VPCwczb4K~KJLT7F`nyO!r}tQbN*O=O z5{=udqo6PyRJGJo3VUMN=n=YM}#o6TGRonOUk-$Te0S^3S?qS{iFRh|@EeOuy6G<(Uh z5?7sRzEw{}SGc+t`gx9EohBODj6g8K+SH{UaeaNguk68t2S51WgV$ewT_Y7+w{G3F zYnM9CCg%%Coq;;AQ?0IeHLkvE+Vf`&3Q8Q_se9#LQ0 zT(5dnSl92e2|b;9QshatNey#8Ei9h1o2MgHtkGb!R0ZzZg;FvKL*5!(73!_6(_S#% zJdsGrNG1|TL?iPp5KMs9$XZudmxhBkZrtcosk)YYBifdfkyGbcZXZX)`YO;Q-6Q@OwdA$+Go0866R4R4B z)LYZp1$hvNqJX;xl-)6?f2xrRJqAfuT*DVy%vNRAShHTuTi2%4_2|K)`fkdjS6iXo zscD9Hlb%Vc+wOcyX^XIuwSZ2y;%4qYx!VqMIxWd4b2=502Z5LieEPySzMsupfS9us z)!`{_nkAQ`Rt>onrz`>pAb? z+|<~TkNT+-0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1PUv__W~5w zo4p}`00IagfB*srAb&s%KZ8B7cN{_T3V_+T6}9D z5rL2h=u%(2cyUEVMNd!9g$oy|tE)X8E-rh9x3=9m|o5++>%9JTn9)9>??V_)* z@9f#LO7Yzbi7^%^59HXYs;V|`-aKc{99^}p3d_sO6}aDj|9umnmn~biY11a<*}He| zwQJXA&Ybysr4V!>M^Xk>B8yXsP^}hDnYfG0dZES4R)jKpa{zapTojUsdomH<3Czis?#GZFO~Z&p-dXZmTnA&Zs|=B0$d=UrYmrhlg+9 zzO7eRdw3f~fnWl3NlA&iz{idqQ;>Bj)YQ~$*|J4p+Lf*gX!h*c&CSh^Jo1RH(cQau zx3#so^6(acunF9{b?c2c-q^5V!-Ee#sLNg#c6WF8u3fu2J3C!Xedd{G(#iACLl3DQ zS6RJ%{PD-N7xiEcA3ogL+NzlA&0|tjeC5iOPd)XN-j>61fuleay|ijy8@0e9TY zx~-$5qv}Vf%iyX(fm@vmdkLOAc~arnM&~6rX$yxeD?Yfe;Gl(p8MsrLGI! zG*6eeE@|(TpJ^Wb^r;^!)fHB?Yu2oJ^wCGBPMx}E&z=(}PH2zGC^P`FcI{f-U#4%Q z6@6x`Tet4qxpT*lA5T__^r#4w7Pz4r=s0@xsK(SZxTffQ`t)gCN&2zzi6@@W@N|J2 z!|o8sPQZ3JvMcUeN+TGbeDaCLH#8)u+d+ABrzpy6&_lsmBh^X>rLzORm`0`cdpAqqiOnhw_OiiTe^%i%Axd6 zKmGKrx88c}vBzF~@kM3Ww{M>rvv$?MTLeNVVB@t$7<4h~skp0=x*cpD-2xNlQ9T;m zP)Ar@X$@}Z5sm`)cfb2xJ3{R{9<3Wk-FbU|sST<}U4AXD_V6}}0>K1mT_1ykg9^1~ zwuav7($qkQu9a!irm1&eAE#*GOyhJ)Idtfd8D-OztsnH1p})UBih{Jc2nBSls-LSM zsGzBN7fnq~_6j!|y8d;MYnVcpxAJJ<;+x<6=AAotwABPt6T3B7Ve%+_)~s22a-&C) z*RNk!$K~?n%X)-Zgti>AQy`cCtq7}uGj$nkKSEcb3DCL_m8gdpX0I17UVP`BcXVZ6 zxpGBMT9l}Mw4PQgj|TOeEn^*l&OHOGzO@_3XMLih;9=T&2?KT&});)-{&79^apq(_ast5wXhml|{nLe|%Sgi)&M{W77RE^2a!$)K37fUX|5=A8HzAu&n<+ji{S9?X~r z!8uCjowmkEKml2O=&yb4YpYhRQhe5(XnNiU4jkau3}SGegBjAaI2&liTv1rYuX7Xwb&ZhSe3jIYL-WHIO zoxrxLck~pYKGEFN*pgihl!}>v2Bp<&)@#g;i^DMj1Z%DY1R^Y;0cbrkBtS>_6sBxC z0XiiQ8xaV-0MR-0rzrad5}>oUqa*@h5YUjc@0{r{w2e08D8K{5904hgz+?(2I_tak z^c9o(u4(-qqMBl+-07Rj_)Bw>d13?+)dU4- zB_2F@kN`ayCnSJ)zR+2eh=JHXEavFujhMS)NXr;N8=c1Wzh>LI_q!Js{5?J5TL(N zt}js17qDwZe@lQb>WIPB5vvD=_k>%&H|B(yEq2|WMWVB%U?nO7`U8jho;&@`as8^H z{;rX8B`SwNJ5vaRZajLzD5=hZGmqqq*m$&_TIeCNeU5BD#&x+&h@;HPW?pS( zXQFrAX48tRpxuj1K0FB zv*MeX#K;K*6QFh2_NhgRKeU!iM;DnknOB>~ndn`&*}MhqrqrcuHs^|MgR`tRL+NJ(uSM4!HwYFi-#<BLun5)9PI_JbWcjrH?qq@3U4~ol6%ggj{isto{D_*B~w(P8t z^-KlE&(u9<%haIzQ>oFqOP#H?>vknm8S*0#O99RLQAE}kUJczD8rHv&p{}kjeTl61 zVEud0`hr6(r6uG46qu9!R!VR8_v@Jp;8o2v#eAsdTFa!CS5ThBPnY@g=j*#UFJHc_ zKT9&H4D1|%2?WNvW}~AD*;+=&{|$^U-eUf}>14UR zG$VI`V15rg_jXVN0yzq(|E`5Wxf~fO9x4F>bf``TjX?kb1ilg=K!0Vy8UhF)5Gn!x zG3Zb=k;Y^sprP1BixyQ@R=P^*XaC;b-gD>9&6+i9_UzdgE?m%)2Aju}x_R@a{z$2- zxW)~XO<(+=;a#oN*48dqu)sNzU}`>d=FH&W;DmeEWTAx%7p5q_c=6(jiV8hE(Z0qW zp^T0?XMbL~a;3dpUtXWtq6TZHDx=!;s)y-zFvPNW8>XBR6O`R#GJp2jXLIJv(Vq!4 z6}s{$(Jsk0r52kIT=kopeNUy?yAD~+cAaJ0Ftai?uXcQ9t#iJY_O7A)k+*-obN}7B z03#zQzQ;+&VpLV9Icr)`qHAAzYmQ5=_OzO8rns#{E6Sj3TD+B*vflJ!NFi9q?JQSS zRc+q9S<$4Yr^k70nnS5*t7X};Wy_Z@fA!T@oxxf+c2iT6zKuuArcIkP`O;PVKu|`vmOmQ{L7S|uP z)}OJ~+zhi-ZxuMqzRazA;J|?_g0;R0?y0Aq((V)p)DksPpDX6MqGjDNHCNDUTNCHk+aqS8hA8|y?eJpm8n4))IDFn ze*LLar_@{5TkqbLsK}+gPn$MP#dq!6rJ!sZpyC@gY&d=TwBqj@Z@gi;c-s2((@(2& z?aZ9rYz+lFRc>}yQ&Y2L%a*fe&$hOX^iiyZ=6*P_A|z}loIV;l4WqF zJ2N|@vonubcjokNEzT4IbPUhCE_8Lc)U)$FHr=|)pvAe>rkIub`g%nrlfm5Tnq7bR z@L^S}L=8u*S+mB*O2t#HtLuH~(j{$G4bI}G66H}12M-?9R^9(vcQ#KS3F^XYh(@te z<1MC$UiKWu9n!hYLbyxiheZF*ZS+N3DDZ3uba}% zNwk%)5@rDcbePXhmTl8bsNSf?kzM5#1U1N@`%|$%-9TqR)LRoER94H06DRiU+2bs( z5$fljdrkwgO4QH$Z@>NawQJXG28|lGw6v%br-Dj6fBw8{fJJqheygI!_#W;F;wD9} zwnDR#EZvnYqqoWG^s>m%Hp!IIj&$sM_wKbZ&ZcXVOVt)v&`d3+N>YI9tR<^iopjYK zcC|+X)B3qYnaz1uir&iH;+S}CTW-@?39|qJI?QJ$o3`l=ROD4>O5+U9^18|Om`)?1 zdYY$O`h^!>aNfPzs(_*t6}OACxDxGKZw9+nE5G0QOGSnHL~~PPi*HL5u+$O_XWQM` znziDs+-yyj?kt<>da^pzFc*<|E~osqg|=08r?$3qikqrjmDn1bTg@I#PT!gph?QUC z?E1*mlK@S*(bL*}`}XNc=J&q$Jrz817O<^Vc0`C4x_*+a1 zQwwA<0nSvYz^ch@>YZu&onGxv^k%D_&gDDhE5+^|5EJKIr${n;p@@j zym|BV!@e^rc{7`)diUj>R;aS7N;BAe582dgSrpt|(+X1;cZqr1lTOWI(Ttadh6a6> zXay~1PIW1K&46q5I`UZ0RnUoiqwGs z0tnBbRH{S(0R(~&AV3G9NF4|ufIuDu2+(;zrOIFgP7c*?WiCK4medk`0fKe( z&ml*E00J=;AVA0T#Bx{&AP{{40(A7xAxD4!0x=aJK*#jNa##o;5Pbmxbo9?5M}PnV zF%^hufNpHASioF>m|n9S76L^n5Yu2?l;@IzMgW1B2@s%Tc0xHE1Q3Xi00BBa=aM5q z0D+hZ5TIjrLOC1+5QvWe0XjbCk|RMN{sRB{CmUZY(zyTx>-b;Z93cV-L{y+WqV1;H zQ5UGKt*xu8(@~U^l=SxYo;h=7aBwi{2NkOJPn|lop`oF&vT}5ER1IruYwPIf2vrMd z%!C32=n09)5U@a5S(&27vSrJjc;X3Ft+$<>odW{{SFc{}@9z(IXT@6Gj2ScTzyJQV zYuDD))C>;~i{a?eqvF+Pp?O=ZFi|`1Z98^uCrU@{tVO@QvuDrVvSmwqd;7~Tzif_1 zDH}FyIDPtbYin!tk1rHQuzL0CB}m%7X=!zJwffe9?x(0L6Q)SJySpv2#*@S@{GxV=+QIXr zFluLv_GTgQ!=Ik`Ns-P4$U=)E;S}JbHJs-q&aE068oF`gh8|_jojcbYr|I`;yfn^- zUD#t2rn=IC9T^!hdltCZgwKkA%Zh!_2SQNh?7QdeZ2NcE<`3>fD_?d9tUcM+j!# z-Q~-dnRgf9C7~G{B0Y5IkaOOh*aO@JRTV&h09^oNcHtwSNxIC_^>GO|dA*FaZ*q5kMgC0tD;46SD&Z5I`V10RnV( zZj?d*0R-|cK!DCWF*`s20R*xWAV6p5MkxdkKp^h|1n9gIvjYSW2%*68KVH`msks0I z>kwW=GzkF&5Ev66Kyw`+fB*s^6(B%|^u*9C1Q0-g0L?Xk00IbvRDb{-(i20o5I_I{ z0yNhE0+|YYy8Z`$7pb`bnI0hd!ze(o4&zy&O$Z=>fCLE8Tm}drfIvtE2+$!tF*FMS z1P~}$^OHlrAWCx~AbvYhdk5^M1@+fP!(eBLre5K(LP4 z3FUAQKp;K>1nBsjOO6Bq1Y#yYfR5P-y&1U~%m(;p=gGybu;sj(#nhr=NtfB*srAb_dRS8| z06@>%%VUpPk*}_;p^h_s84GGbA7QW=0F?cVTMEUfbHX97J!}ACtkrX3090S+M*)Z; z0x-q}z%3g9yzpwpZg+KKyWjT#td*4&Ki692|7mJ!R{=}C6c|SC@$m2C^1}45*Oxxn ztfZ4z%!cGZ4gR@!JOVA+(X{|e>W4!FVCf=2MJuZ`30fFp{Ts-Ux0ca3&kxW6IW6|- z;5#Yx=4$T#p;zy7Fyso0yidJ@+kviyN(kA66rP3YQAqQ9(NW7ez~qe2a5^BDz*wn+ z0`E(8INpo{U`wvcdKCD0A)@?xB?=_!P&SDV2A9pr-$6irVyn{v?JSPF*D>LZ{tDne z!3iVInjz)Ql@G?*;I9Y1s;vG?zTp$S;kX1n`r3*1Yt_5=3i8WWe*#Uz3yodl$<=&5 zP3K1q*|bAEdPAq6T^*!?Y5s`d4!zi>vWV4eNfR@Be4~3h28*M`y+gWfS zNR@aSWUre+KdFkjH(oAEc3ik)ggBFNj&*f4v&KkJkcl+OaG)rGZ6&id$vy2oxpDsG zH^`(ch0&E8z&KLBnK|RbzCdt$5Tcpz7~{Tn)7vHg1Iz46^OT|!=i43V__U1ZW!QD) zO%L%8T4IO99eJi7)gbH8c;2L}h2qD?tXk*5G15-=y!QsFd}k6~cH&HLyy};cX~9#m z-KnCfxNQ(YOOU3rXCcVV&{u8t&_pgnveGqOx3UB($`@DF1D6TCxVeRZ_6{^9s%tw4Ge?C2l0@{Z=p&x9+llO15zBKyzPiM|uXmor?pxg3T z)(Z9xV$a?YmVm;>gNA(t3sP&8!gK}2Js%S+0DONkhWxku0OWU5s7bFCePAKQo#gi@ zc*z*4oQMn6h`%!73<9|!6~BGF*8xdjL^<7ywg^W}fRkBt5(V^3Rb3RT9#$t0{F3(8 zd&IMb(K*<+Y%e=4o-wxyOAo3!2%ar<3n|ozqx0U(5BFkG_MMHZ6+A3<&gu8Ytmm1ehWjc>TSUoNM21O&OlQe?|FKS$NVHK^-fj=wHB;DRu_^@#e#UG`(p}&~$ z*g?-%BZAT=l#Zz`X9A&8DUwc>?!Gb1G3(3ym%j`Bla*v~TPBS*mNoWwOwVaHN4ueE zKS)S(IZ%FKa{_+f@d;iM-+3MAFM?hhh4q|ktGaewvvuEn(9KQLNz5g*;!S>{_ID(j zzy1UUq(KAJC?7M?qu#b@WAc7B3h@weo=I+?L*5Ux@|Q~O&E(~GY#*hG`Lk1n<(Z&U z+M{IRB4F6&P{9V&1KxKh&){n1btmgFC6}fKq96I!?f@dIyhzLp>0(QGxDC&YQl^5l zSk55!CofjyI#X?*tz{2yYjaDACw?#&_dk=5-LqEk-p+efq`Bu_rQ9bRhzr3hqPn74 z5>{#k?1C*bIPxoLl=xaxC};~#eKQjKk!=@`$6b*(&Y%<_qP5owwnEt)N{?;*KVvlB zy#Wum=g-*_d&-K3uYf0~bav1pt!#7NX=t|$ymVZ8FC^w{o^GUejJ(7jvP`oY>JL<~n71=6~<*Puv&l<5#H`VBssvY0Zy=+GuaJ>w-BA&h{Ue*h9CY1I3@@?$~&V5h%WyD e$N{jc8`0H`AcEju?-Q{ZYXj!Y!{3AtuyFV?me8NwCUw8Xv+gCPz?@q2u>Gp`& z^C-(pPpGrP(n6&q6#7171bJ<{YkBP{Lh!FhwkyY9vB za~*0|yiHvatp>-bqS~(i%R>fVt>!sV4@n&m(Or^6rQKd#YZL|cC{4F)zE(4?Abx5x#R9rWG;zFii|gH;#vaB3U~gRb)3?V=Cz&DJEZO-_v=chZ8BG53ML92vekl+B7+`8C^DtpK>EQ$Eah{2Zq| z>}N>bOMWoBkjHUw;okItkJf&347Rs&uOnApH=yINt$QiI`LW(M-ffFDT;82Dm$s)$ z-lybJZmI7V$zf1(4T6`;O(_U5glB2(9df>L|1e$b8FIdJ2M)ZkIv~uiS~RRq^C>1xdgIi9uBeOd zho$!`hh54Yw(y!Pt)E~-jk0>`SjfXfVyPw+5GY$k^1&CVO?V?9KID)V)j_D%tz`&e z5Kg%9|k%`sU zfmgReXM5pE>zU>DKb~9;_M-+n%ms(kMNHLb@Lmq|U9BqHdAmZ>BvF z{_&)-nBYdAIT|-o8%t&G^_~w;3{_2BD#i2Wk^=WFwEwak{r13$TcNu;bu{$TO2^~) zy3ncRB_H>%sG~_C2ktG7g})i@sU<_TTE?M$TM=TG{|IlJLP3daAG932ULnyPPk1b&5GmNDpJARPSFq5NuAh~YtO(6JX3bTb*#v~wdeXMIiA_)j zBM5`_uBDnbP^79oXldAMd^tg?^TD3^^dl00i?0sX+E+yp0ZS=LpAIcz6Xba*{HHgI zlu@Y!RoVV=I!V3~Dw6NX>UR*;L=6Jd8mGlnG05rc8j=wPrB;M*&qJjmkA80g%O<=6 zQQdWZxP*_)7?7!i5-~9s-izz+%MGCT zMFpS)WRlr#Q<8g=}U_B2!4D*n^)U{!tJX?jLj{?%xY!5oR}90FL%d KyK)=OnZE#WlBKW! literal 0 HcmV?d00001 diff --git a/data/icons/oled/weather/cloudy.png b/data/icons/oled/weather/cloudy.png new file mode 100644 index 0000000000000000000000000000000000000000..7b0b65e218df86d363f9e8f7b15bd3114e1963ec GIT binary patch literal 1255 zcmb7DX;4!K5Z>ntfe;diPy!A|pi#gI1kj)nG$3gbIfRIch#XO_aK!>62;vi{Sj8z& z%cOu9RE#2^XgS7;21TGi$5dP7CI&@C5g3lP2tyy8&h%G*_|5Eov%BB7`)j}P_v2G^ z*XRNOMJVtR;f$?>4vOblb>Uw)5u!bOJpk&yB`-#3;WgusK;#Q>Y#px41z1?ozX3>P z0gQ(OaAW{VsT zrDjR75ly=kA0lFJz89RYZJ8qg zXu8nLBQULhqI4kp21Ab*O(3+aUtE4d?X{>m!wgW(D6?v#j&xBz&g|av59Ue_QeHHs zBPR5kQsy2--w<3q8b@jke2K=KAMnQR6i_g4`m?wu61NEzVhlrN#qk1$KKJ2$8^MR1 z4KTR2awn?iOi{Nzgw6DX~{?l zJ_DgzbH)5irBX zXJ-0bUviHfkn|nfpN&mJ{=KFjkez);JukyG#aZjv2&_VW+|}|50UTPxWQ1~}eBrs_ znj)yQQQAj1>8j2*ZhyTl0He7QEiHcG_v?;V&yk>4`%k@O%aXjpqOuMG%vNjo^~BLM z?KUccxyZW*iW?+#JynUBN%1)c$%e?(cRH_{CT2ri+P+*6E*0uzK=-U~=xrpZpg#ElNX5J>-Yi}cyfM8bCbJqPA%Qtt#HUAV8 zvJ1Ga<#h4Bgx{CMMj(wgrdvO#tb?f=@2@k3;*!S}kX0WB-P`(vYET>JU2U*pi!`h( zZJ08sGTSe?`2>}@rHZze5n}8vG+l`|gJWA2sT$Gh0Fdj=F99X{dYwa zrTu(!s2kP)_Ks#Ai-uK4(9aJcWmWDDf_UUZKg4Bgsf&rz!I@gpkA!=Mt)|#e(uv?) zQ+X3P|BOB8S7YRgBSc&C9L+c#Gi3qf3eIx@pUvWcTn-62mi~pDZHSR!x1TwoI_tl;snktr!DrZ zjrLCLK$Z(<(`Jsd(-$mf4vUo*GQaZb{}~dJ4#!5N|G$BR_;uq35c2%IYCXfV{|4X8 B510S| literal 0 HcmV?d00001 diff --git a/data/icons/oled/weather/fog.png b/data/icons/oled/weather/fog.png new file mode 100644 index 0000000000000000000000000000000000000000..f7b63f758cb393bae76dfab11f9aff122d7485f1 GIT binary patch literal 3004 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 literal 0 HcmV?d00001 diff --git a/data/icons/oled/weather/hail.png b/data/icons/oled/weather/hail.png new file mode 100644 index 0000000000000000000000000000000000000000..2f9dfbf1e118ab5c903883f07176d6a9a5eb9193 GIT binary patch literal 1474 zcmcgseK^y56#xFV*=%_kM)!8bPuV3y^R})bbF;R|%M#H-n^CE}Pj~3nnow6Rs#{Uo zt|#3GDVZX@O;(SJ>n%c8t&4~ul7zLp{=9$OfA4vob3V^G=ks~adCni_1UrzSk6VQU z0O+%rzQI})eRW-=HqI%FK5GHB$0xuCfExuXmU%kb9Og5F0|3bQUduZMz~Wc_7yxNx z0LHlhP|pLfGU;ODR!?msjqM*o*Jw0jeTsMgqiHAl>+EdOEr{v3gfR1 zbqyX~))p}WRsbC{gfcRrIGh$|OSBh4v3z|(gaebsFEc91_-s-N+m^$&^{eWcx~m~2 zKvpm-9E+V3r}ejuE*BTKS}je+cUpG%ae4<1Mg%`gzMD_ftgZTOjlB2Dt%`^vCjJm! zIDL%d;i``pIvPDK!ezVC76Q>D#YkNh?}Opw`;bCp&A~!7gZhwHh^UF^xQ{xjCr8&8 zm@vTsV(U=42+3S{aO(O>xbS9B3x@Dx1`}HPIQTIb+`hI<;k0M>_EvB zt-Kl`3S1iAWI=mLv>#D|-nY%rW-jYCEbr}2ykm^OUk%ui3(#Sf&7ftRkB1k?`!A^! zAhVjDi^cx}E;AB|X;DU0(A{VA=y<~(NcBhUE?B4shGwQ)uu;&N%^IW1vkV+L7I07m z+Grp2G!bcQFBvku1t>0k>vOWuatTrtPT>BkOF(k;rOET>in_tr>gA+11AMDK-VwOT z`xtPjo4fQUjdY#g?^UvYRePzdJ}7%$Mf+o#p^Dk&gTu8iAgQP~`GcJQXI8@4E?}x2(J0OH$ju z4$NME#T!!HvA_L#M}mdaQ#CT+u6i?PzxX06S+tzqCpozYHX$&?O4?I2_ZU@K|6Gz%Qlj?PwZEfL&jL!*;#LA(?N3TikwWGHOFlVi(peq zmUPA|rI_)`Qcd>!dHtfWIcH}Zz1~LDY^GUv~&_j3vQ^{mu#C+1f1o4S6al6z1TY!ZETeSkf Mq6hk3`;jaD2UC2S$^ZZW literal 0 HcmV?d00001 diff --git a/data/icons/oled/weather/partly-cloudy-day.png b/data/icons/oled/weather/partly-cloudy-day.png new file mode 100644 index 0000000000000000000000000000000000000000..09f04b28f63b1daddc8fe8303da828858ce3b64c GIT binary patch literal 2610 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 V|AwVVSeMQKA*`^Vy1>}X-vOh{V2l6& literal 0 HcmV?d00001 diff --git a/data/icons/oled/weather/rain.png b/data/icons/oled/weather/rain.png new file mode 100644 index 0000000000000000000000000000000000000000..8e2c1c273a4e1971102b1c0248c46f730d8e657e GIT binary patch literal 1169 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 AS^xk5 literal 0 HcmV?d00001 diff --git a/data/icons/oled/weather/snow.png b/data/icons/oled/weather/snow.png new file mode 100644 index 0000000000000000000000000000000000000000..36ac0f1843b688e5308334e095fb9d7012ba9f15 GIT binary patch literal 4151 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 S5QNmp7XV8F$?TCSmH96wt!nN7 literal 0 HcmV?d00001 diff --git a/data/icons/oled/weather/wind.png b/data/icons/oled/weather/wind.png new file mode 100644 index 0000000000000000000000000000000000000000..d13baeb411e7849a08508256c296c9e9765bb727 GIT binary patch literal 2691 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 literal 0 HcmV?d00001 diff --git a/data/locale/deutsch.locale b/data/locale/deutsch.locale index 7969867ce..df6d505ea 100644 --- a/data/locale/deutsch.locale +++ b/data/locale/deutsch.locale @@ -886,10 +886,24 @@ fsk.from_7 ab 7 fsk.to_12 bis 12 fsk.to_16 bis 16 fsk.to_7 bis 7 +glcd.align_center zentriert +glcd.align_channel Sender ausrichten +glcd.align_duration Sendungsdauer ausrichten +glcd.align_end Sendungsende ausrichten +glcd.align_epg EPG ausrichten +glcd.align_left links +glcd.align_none keine +glcd.align_right rechts +glcd.align_start Sendungsstart ausrichten +glcd.align_time Zeit ausrichten +glcd.bar_width Fortschrittsbalken-Weite +glcd.bar_x_position Fortschrittsbalken x-Position +glcd.bar_y_position Fortschrittsbalken y-Position glcd.brightness Helligkeit -glcd.brightness_standby Helligkeit in Standby -glcd.clock.analog analog -glcd.clock.digital_hm digital +glcd.brightness_standby Helligkeit im Standby +glcd.brightness_dim Dimmen +glcd.brightness_dim_time Dimmen nach +glcd.brightness_settings Helligkeits-Einstellungen glcd.color.amber Amber glcd.color.black Schwarz glcd.color.blue Blau @@ -911,25 +925,62 @@ glcd.color.red Rot glcd.color.teal Teal glcd.color.white Weiß glcd.color.yellow Gelb +glcd.channel_x_position Sender x-Position +glcd.channel_y_position Sender y-Position +glcd.digital_clock_y_position Digitaluhr y-Position glcd.display Display-Typ +glcd.duration_x_position Sendungsdauer x-Position +glcd.duration_y_position Sendungsdauer y-Position glcd.enable GraphLCD aktiv +glcd.end_x_position Sendungsende x-Position +glcd.end_y_position Sendungsende y-Position +glcd.epg_x_position EPG x-Position +glcd.epg_y_position EPG x-Position glcd.font Schrift +glcd.font_autoresize Automatische SChriftgröße glcd.head GraphLCD-Unterstützung +glcd.logo_x_position Senderlogo x-Position +glcd.logo_y_position Senderlogo y-Position glcd.mirror_osd OSD-Menü auf GraphLCD anzeigen glcd.mirror_video Videobild auf GraphLCD anzeigen +glcd.position_settings Positions-Einstellungen glcd.restart Neu erkennen glcd.scroll_speed Scroll-Geschwindigkeit glcd.select.bar Fortschrittsbalken-Farbe glcd.select.bg Hintergrund-Farbe glcd.select.fg Vordergrund-Farbe -glcd.show_logo Sender-Logo anzeigen +glcd.show_duration Sendungsdauer zeigen +glcd.show_end Sendungsende zeigen +glcd.show_logo Senderlogo anzeigen +glcd.show_progressbar Fortschrittsbalken +glcd.show_start Sendungsstart zeigen +glcd.show_time Uhrzeit anzeigen +glcd.show_weather Wetter anzeigen +glcd.simple_clock_y_position Einfache Uhr y-Position glcd.size_bar Fortschrittsbalken-Größe glcd.size_channel Sender-Größe +glcd.size_duration Sendungsdauer-Größe +glcd.size_end Sendungsende-Größe glcd.size_epg EPG-Größe -glcd.size_logo Logo-Größe +glcd.size_logo Senderlogo-Größe +glcd.size_simple_clock Einfache Uhr-Größe +glcd.size_start Sendungsstart-Größe glcd.size_time Uhrzeit-Größe -glcd.size_time_standby Uhrzeit-Größe in Standby -glcd.time_in_standby Zeitanzeige in Standby +glcd.size_time_standby Uhrzeit-Größe im Standby +glcd.theme Thema +glcd.theme_position_settings Positions-Einstellungen +glcd.theme_settings Thema-Einstellungen +glcd.standby_analog_clock Analoge Uhr +glcd.standby_digital_clock Digitale Uhr +glcd.standby_lcd_clock LCD-Uhr +glcd.standby_led_clock LED-Uhr +glcd.standby_settings Standby-Einstellungen +glcd.standby_weather Wetter im Standby +glcd.start_x_position Sendungsstart x-Position +glcd.start_y_position Sendungsstart y-Position +glcd.time_in_standby Zeitanzeige im Standby +glcd.time_x_position Uhrzeit x-Position +glcd.time_y_position Uhrzeit y-Position glcd.volume Lautstärke hdd_10min 10 min. hdd_1min 1 min. @@ -1817,6 +1868,7 @@ menu.hint_volume_digits Zifferndarstellung der Lautstärkeanzeige ein- oder auss menu.hint_volume_pos Wählen Sie die Position der Lautstärkeanzeige aus menu.hint_volume_size Wählen Sie die Höhe der Lautstärkeanzeige menu.hint_weather_api_key Geben Sie den Dark Sky API Schlüssel ein. Eine leere Eingabe schaltet die Wetter-Unterstützung aus +menu.hint_weather_country menu.hint_weather_enabled Schaltet die Wetter-Unterstützung (darksky.net) ein bzw. aus menu.hint_weather_location Wählen Sie eine Stadt in ihrer Nähe zur Anzeige der Wetterdaten aus menu.hint_webradio_setup Hier konfigurierte WebRadio-Kanäle finden Sie in der Kanalverwaltung. @@ -2931,6 +2983,9 @@ videomenu.zappingmode Umschaltverhalten videomenu.zappingmode_mute Schwarzes Bild videomenu.zappingmode_hold Standbild weather.api_key Wetter API Schlüssel (Dark Sky) +weather.country Länderwahl +weather.country_deutschland Deutschland +weather.country_norway Norwegen weather.enabled Wetter-Unterstützung weather.location Wetter-Standort webradio.head WebRadio diff --git a/data/locale/english.locale b/data/locale/english.locale index c498e3ecd..1bcc260c1 100644 --- a/data/locale/english.locale +++ b/data/locale/english.locale @@ -888,8 +888,6 @@ fsk.to_16 to 16 fsk.to_7 to 7 glcd.brightness Brightness glcd.brightness_standby Brightness in standby -glcd.clock.analog analog -glcd.clock.digital_hm digital glcd.color.amber Amber glcd.color.black Black glcd.color.blue Blue diff --git a/data/othemes/Makefile.am b/data/othemes/Makefile.am new file mode 100644 index 000000000..655c7d8c9 --- /dev/null +++ b/data/othemes/Makefile.am @@ -0,0 +1,9 @@ +installdir = $(THEMESDIR) + +install_DATA = \ + advanced.otheme \ + default.otheme \ + easy.otheme \ + medium.otheme \ + simple.otheme \ + weather.otheme diff --git a/data/othemes/advanced.otheme b/data/othemes/advanced.otheme new file mode 100644 index 000000000..a0033ad4e --- /dev/null +++ b/data/othemes/advanced.otheme @@ -0,0 +1,72 @@ +# align none 0, align left 1, align center 2, align right 3 +# if align > 0 x position will be ignore +# if glcd_background != "" background color will be ignore +# if glcd_position_settings != false this allow to edit position settings over gui +glcd_color_fg_red=100 +glcd_color_fg_green=100 +glcd_color_fg_blue=100 +glcd_color_bg_red=0 +glcd_color_bg_green=0 +glcd_color_bg_blue=0 +glcd_color_bar_red=0 +glcd_color_bar_green=0 +glcd_color_bar_blue=100 +glcd_font=/usr/share/fonts/neutrino.ttf +glcd_background=/share/tuxbox/neutrino/icons/oled/advanced.png +glcd_align_channel=2 +glcd_align_epg=2 +glcd_align_duration=3 +glcd_align_start=0 +glcd_align_end=3 +glcd_align_time=1 +glcd_show_progressbar=true +glcd_show_duration=true +glcd_show_start=false +glcd_show_end=true +glcd_show_time=true +glcd_show_weather=false +glcd_percent_channel=22 +glcd_channel_x_position=0 +glcd_channel_y_position=22 +glcd_percent_epg=15 +glcd_epg_x_position=0 +glcd_epg_y_position=133 +glcd_percent_duration=14 +glcd_duration_x_position=0 +glcd_duration_y_position=261 +glcd_percent_start=0 +glcd_start_x_position=0 +glcd_start_y_position=0 +glcd_percent_end=14 +glcd_end_x_position=0 +glcd_end_y_position=224 +glcd_percent_time=14 +glcd_time_x_position=0 +glcd_time_y_position=261 +glcd_percent_bar=22 +glcd_bar_x_position=23 +glcd_bar_y_position=216 +glcd_bar_width=311 +glcd_percent_logo=22 +glcd_logo_x_position=0 +glcd_logo_y_position=22 +glcd_percent_smalltext=4 +glcd_smalltext_y_position=6 +glcd_rec_icon_x_position=398 +glcd_mute_icon_x_position=273 +glcd_ts_icon_x_position=443 +glcd_timer_icon_x_position=333 +glcd_ecm_icon_x_position=100 +glcd_dd_icon_x_position=238 +glcd_txt_icon_x_position=193 +glcd_cam_icon_x_position=148 +glcd_digital_clock_y_position=20 +glcd_size_simple_clock=40 +glcd_simple_clock_y_position=20 +glcd_weather_x_position_current=0 +glcd_weather_x_position_next=0 +glcd_weather_y_position=0 +glcd_weather_x_position_current_standby=10 +glcd_weather_x_position_next_standby=340 +glcd_weather_y_position_standby=175 +glcd_position_settings=true diff --git a/data/othemes/default.otheme b/data/othemes/default.otheme new file mode 100644 index 000000000..c859a3be4 --- /dev/null +++ b/data/othemes/default.otheme @@ -0,0 +1,72 @@ +# align none 0, align left 1, align center 2, align right 3 +# if align > 0 x position will be ignore +# if glcd_background != "" background color will be ignore +# if glcd_position_settings != false this allow to edit position settings over gui +glcd_color_fg_red=100 +glcd_color_fg_green=100 +glcd_color_fg_blue=100 +glcd_color_bg_red=0 +glcd_color_bg_green=0 +glcd_color_bg_blue=0 +glcd_color_bar_red=0 +glcd_color_bar_green=0 +glcd_color_bar_blue=100 +glcd_font=/usr/share/fonts/neutrino.ttf +glcd_background= +glcd_align_channel=2 +glcd_align_epg=2 +glcd_align_duration=0 +glcd_align_start=0 +glcd_align_end=0 +glcd_align_time=2 +glcd_show_progressbar=true +glcd_show_duration=false +glcd_show_start=false +glcd_show_end=false +glcd_show_time=true +glcd_show_weather=false +glcd_percent_channel=25 +glcd_channel_x_position=0 +glcd_channel_y_position=25 +glcd_percent_epg=15 +glcd_epg_x_position=0 +glcd_epg_y_position=130 +glcd_percent_duration=0 +glcd_duration_x_position=0 +glcd_duration_y_position=0 +glcd_percent_start=0 +glcd_start_x_position=0 +glcd_start_y_position=0 +glcd_percent_end=0 +glcd_end_x_position=0 +glcd_end_y_position=0 +glcd_percent_time=25 +glcd_time_x_position=0 +glcd_time_y_position=230 +glcd_percent_bar=20 +glcd_bar_x_position=0 +glcd_bar_y_position=210 +glcd_bar_width=485 +glcd_percent_logo=25 +glcd_logo_x_position=0 +glcd_logo_y_position=25 +glcd_percent_smalltext=4 +glcd_smalltext_y_position=6 +glcd_rec_icon_x_position=398 +glcd_mute_icon_x_position=273 +glcd_ts_icon_x_position=443 +glcd_timer_icon_x_position=333 +glcd_ecm_icon_x_position=100 +glcd_dd_icon_x_position=238 +glcd_txt_icon_x_position=193 +glcd_cam_icon_x_position=148 +glcd_digital_clock_y_position=20 +glcd_size_simple_clock=40 +glcd_simple_clock_y_position=20 +glcd_weather_x_position_current=0 +glcd_weather_x_position_next=0 +glcd_weather_y_position=0 +glcd_weather_x_position_current_standby=10 +glcd_weather_x_position_next_standby=340 +glcd_weather_y_position_standby=175 +glcd_position_settings=true diff --git a/data/othemes/easy.otheme b/data/othemes/easy.otheme new file mode 100644 index 000000000..f92e4aeae --- /dev/null +++ b/data/othemes/easy.otheme @@ -0,0 +1,72 @@ +# align none 0, align left 1, align center 2, align right 3 +# if align > 0 x position will be ignore +# if glcd_background != "" background color will be ignore +# if glcd_position_settings != false this allow to edit position settings over gui +glcd_color_fg_red=100 +glcd_color_fg_green=100 +glcd_color_fg_blue=100 +glcd_color_bg_red=0 +glcd_color_bg_green=0 +glcd_color_bg_blue=0 +glcd_color_bar_red=0 +glcd_color_bar_green=0 +glcd_color_bar_blue=100 +glcd_font=/usr/share/fonts/neutrino.ttf +glcd_background=/share/tuxbox/neutrino/icons/oled/easy.png +glcd_align_channel=2 +glcd_align_epg=2 +glcd_align_duration=3 +glcd_align_start=0 +glcd_align_end=0 +glcd_align_time=1 +glcd_show_progressbar=false +glcd_show_duration=true +glcd_show_start=false +glcd_show_end=false +glcd_show_time=true +glcd_show_weather=false +glcd_percent_channel=22 +glcd_channel_x_position=0 +glcd_channel_y_position=22 +glcd_percent_epg=18 +glcd_epg_x_position=0 +glcd_epg_y_position=152 +glcd_percent_duration=14 +glcd_duration_x_position=0 +glcd_duration_y_position=261 +glcd_percent_start=0 +glcd_start_x_position=0 +glcd_start_y_position=0 +glcd_percent_end=0 +glcd_end_x_position=0 +glcd_end_y_position=0 +glcd_percent_time=14 +glcd_time_x_position=0 +glcd_time_y_position=261 +glcd_percent_bar=0 +glcd_bar_x_position=0 +glcd_bar_y_position=0 +glcd_bar_width=0 +glcd_percent_logo=22 +glcd_logo_x_position=0 +glcd_logo_y_position=22 +glcd_percent_smalltext=4 +glcd_smalltext_y_position=6 +glcd_rec_icon_x_position=398 +glcd_mute_icon_x_position=273 +glcd_ts_icon_x_position=443 +glcd_timer_icon_x_position=333 +glcd_ecm_icon_x_position=100 +glcd_dd_icon_x_position=238 +glcd_txt_icon_x_position=193 +glcd_cam_icon_x_position=148 +glcd_digital_clock_y_position=20 +glcd_size_simple_clock=40 +glcd_simple_clock_y_position=20 +glcd_weather_x_position_current=0 +glcd_weather_x_position_next=0 +glcd_weather_y_position=0 +glcd_weather_x_position_current_standby=10 +glcd_weather_x_position_next_standby=340 +glcd_weather_y_position_standby=175 +glcd_position_settings=true diff --git a/data/othemes/medium.otheme b/data/othemes/medium.otheme new file mode 100644 index 000000000..a803ac883 --- /dev/null +++ b/data/othemes/medium.otheme @@ -0,0 +1,72 @@ +# align none 0, align left 1, align center 2, align right 3 +# if align > 0 x position will be ignore +# if glcd_background != "" background color will be ignore +# if glcd_position_settings != false this allow to edit position settings over gui +glcd_color_fg_red=100 +glcd_color_fg_green=100 +glcd_color_fg_blue=100 +glcd_color_bg_red=0 +glcd_color_bg_green=0 +glcd_color_bg_blue=0 +glcd_color_bar_red=0 +glcd_color_bar_green=0 +glcd_color_bar_blue=100 +glcd_font=/usr/share/fonts/neutrino.ttf +glcd_background=/share/tuxbox/neutrino/icons/oled/medium.png +glcd_align_channel=2 +glcd_align_epg=2 +glcd_align_duration=3 +glcd_align_start=0 +glcd_align_end=3 +glcd_align_time=1 +glcd_show_progressbar=true +glcd_show_duration=false +glcd_show_start=false +glcd_show_end=true +glcd_show_time=true +glcd_show_weather=false +glcd_percent_channel=22 +glcd_channel_x_position=0 +glcd_channel_y_position=22 +glcd_percent_epg=14 +glcd_epg_x_position=0 +glcd_epg_y_position=198 +glcd_percent_duration=14 +glcd_duration_x_position=0 +glcd_duration_y_position=261 +glcd_percent_start=0 +glcd_start_x_position=0 +glcd_start_y_position=0 +glcd_percent_end=14 +glcd_end_x_position=0 +glcd_end_y_position=116 +glcd_percent_time=14 +glcd_time_x_position=0 +glcd_time_y_position=116 +glcd_percent_bar=14 +glcd_bar_x_position=29 +glcd_bar_y_position=288 +glcd_bar_width=450 +glcd_percent_logo=22 +glcd_logo_x_position=0 +glcd_logo_y_position=22 +glcd_percent_smalltext=4 +glcd_smalltext_y_position=6 +glcd_rec_icon_x_position=398 +glcd_mute_icon_x_position=273 +glcd_ts_icon_x_position=443 +glcd_timer_icon_x_position=333 +glcd_ecm_icon_x_position=100 +glcd_dd_icon_x_position=238 +glcd_txt_icon_x_position=193 +glcd_cam_icon_x_position=148 +glcd_digital_clock_y_position=20 +glcd_size_simple_clock=40 +glcd_simple_clock_y_position=20 +glcd_weather_x_position_current=0 +glcd_weather_x_position_next=0 +glcd_weather_y_position=0 +glcd_weather_x_position_current_standby=10 +glcd_weather_x_position_next_standby=340 +glcd_weather_y_position_standby=175 +glcd_position_settings=true diff --git a/data/othemes/simple.otheme b/data/othemes/simple.otheme new file mode 100644 index 000000000..2836d53b9 --- /dev/null +++ b/data/othemes/simple.otheme @@ -0,0 +1,72 @@ +# align none 0, align left 1, align center 2, align right 3 +# if align > 0 x position will be ignore +# if glcd_background != "" background color will be ignore +# if glcd_position_settings != false this allow to edit position settings over gui +glcd_color_fg_red=100 +glcd_color_fg_green=100 +glcd_color_fg_blue=100 +glcd_color_bg_red=0 +glcd_color_bg_green=0 +glcd_color_bg_blue=0 +glcd_color_bar_red=0 +glcd_color_bar_green=0 +glcd_color_bar_blue=100 +glcd_font=/usr/share/fonts/neutrino.ttf +glcd_background=/share/tuxbox/neutrino/icons/oled/simple.png +glcd_align_channel=2 +glcd_align_epg=2 +glcd_align_duration=0 +glcd_align_start=0 +glcd_align_end=0 +glcd_align_time=0 +glcd_show_progressbar=false +glcd_show_duration=false +glcd_show_start=false +glcd_show_end=false +glcd_show_time=false +glcd_show_weather=false +glcd_percent_channel=20 +glcd_channel_x_position=0 +glcd_channel_y_position=51 +glcd_percent_epg=16 +glcd_epg_x_position=0 +glcd_epg_y_position=241 +glcd_percent_duration=0 +glcd_duration_x_position=0 +glcd_duration_y_position=0 +glcd_percent_start=0 +glcd_start_x_position=0 +glcd_start_y_position=0 +glcd_percent_end=14 +glcd_end_x_position=0 +glcd_end_y_position=0 +glcd_percent_time=0 +glcd_time_x_position=0 +glcd_time_y_position=0 +glcd_percent_bar=0 +glcd_bar_x_position=0 +glcd_bar_y_position=0 +glcd_bar_width=0 +glcd_percent_logo=20 +glcd_logo_x_position=0 +glcd_logo_y_position=51 +glcd_percent_smalltext=4 +glcd_smalltext_y_position=6 +glcd_rec_icon_x_position=398 +glcd_mute_icon_x_position=273 +glcd_ts_icon_x_position=443 +glcd_timer_icon_x_position=333 +glcd_ecm_icon_x_position=100 +glcd_dd_icon_x_position=238 +glcd_txt_icon_x_position=193 +glcd_cam_icon_x_position=148 +glcd_digital_clock_y_position=20 +glcd_size_simple_clock=40 +glcd_simple_clock_y_position=20 +glcd_weather_x_position_current=0 +glcd_weather_x_position_next=0 +glcd_weather_y_position=0 +glcd_weather_x_position_current_standby=10 +glcd_weather_x_position_next_standby=340 +glcd_weather_y_position_standby=175 +glcd_position_settings=true diff --git a/data/othemes/weather.otheme b/data/othemes/weather.otheme new file mode 100644 index 000000000..216f12207 --- /dev/null +++ b/data/othemes/weather.otheme @@ -0,0 +1,72 @@ +# align none 0, align left 1, align center 2, align right 3 +# if align > 0 x position will be ignore +# if glcd_background != "" background color will be ignore +# if glcd_position_settings != false this allow to edit position settings over gui +glcd_color_fg_red=100 +glcd_color_fg_green=100 +glcd_color_fg_blue=100 +glcd_color_bg_red=0 +glcd_color_bg_green=0 +glcd_color_bg_blue=0 +glcd_color_bar_red=0 +glcd_color_bar_green=0 +glcd_color_bar_blue=100 +glcd_font=/usr/share/fonts/neutrino.ttf +glcd_background=/share/tuxbox/neutrino/icons/oled/weather.png +glcd_align_channel=2 +glcd_align_epg=2 +glcd_align_duration=3 +glcd_align_start=0 +glcd_align_end=3 +glcd_align_time=1 +glcd_show_progressbar=true +glcd_show_duration=false +glcd_show_start=false +glcd_show_end=true +glcd_show_time=false +glcd_show_weather=true +glcd_percent_channel=22 +glcd_channel_x_position=0 +glcd_channel_y_position=22 +glcd_percent_epg=14 +glcd_epg_x_position=0 +glcd_epg_y_position=133 +glcd_percent_duration=14 +glcd_duration_x_position=0 +glcd_duration_y_position=261 +glcd_percent_start=0 +glcd_start_x_position=0 +glcd_start_y_position=0 +glcd_percent_end=14 +glcd_end_x_position=0 +glcd_end_y_position=185 +glcd_percent_time=0 +glcd_time_x_position=0 +glcd_time_y_position=0 +glcd_percent_bar=22 +glcd_bar_x_position=18 +glcd_bar_y_position=201 +glcd_bar_width=313 +glcd_percent_logo=22 +glcd_logo_x_position=0 +glcd_logo_y_position=22 +glcd_percent_smalltext=4 +glcd_smalltext_y_position=6 +glcd_rec_icon_x_position=398 +glcd_mute_icon_x_position=273 +glcd_ts_icon_x_position=443 +glcd_timer_icon_x_position=333 +glcd_ecm_icon_x_position=100 +glcd_dd_icon_x_position=238 +glcd_txt_icon_x_position=193 +glcd_cam_icon_x_position=148 +glcd_digital_clock_y_position=20 +glcd_size_simple_clock=40 +glcd_simple_clock_y_position=20 +glcd_weather_x_position_current=45 +glcd_weather_x_position_next=375 +glcd_weather_y_position=240 +glcd_weather_x_position_current_standby=10 +glcd_weather_x_position_next_standby=340 +glcd_weather_y_position_standby=175 +glcd_position_settings=true diff --git a/data/y-web/Makefile.am b/data/y-web/Makefile.am index 653eaec74..01bb19435 100644 --- a/data/y-web/Makefile.am +++ b/data/y-web/Makefile.am @@ -55,6 +55,7 @@ install_DATA = channels.js \ Y_Settings_automount.yhtm \ Y_Settings_Backup.yhtm \ Y_Settings_buttons.yhtm \ + Y_Settings_glcd.yhtm \ Y_Settings_lcd.yhtm \ Y_Settings_Live.yhtm \ Y_Settings_Menue.yhtm \ @@ -79,6 +80,7 @@ install_DATA = channels.js \ Y_Tools_Cmd.yhtm \ Y_Tools_Flash_Menue.yhtm \ Y_Tools_Flash_Upload.yhtm \ + Y_Tools_Glcd_Screenshot.yhtm \ Y_Tools_Info_Menue.yhtm \ Y_Tools_Installer.yhtm \ Y_Tools_lcshot.yhtm \ diff --git a/data/y-web/Y_Baselib.js b/data/y-web/Y_Baselib.js index e47890961..dcd498964 100644 --- a/data/y-web/Y_Baselib.js +++ b/data/y-web/Y_Baselib.js @@ -505,3 +505,8 @@ function saveTextAsFile(content, filename, filetype) } downloadLink.click(); } + +function glcdscreenshot(_filename) +{ + return loadSyncURL("/control/glcdscreenshot?name="+_filename); +} diff --git a/data/y-web/Y_Boxcontrol_Menue.yhtm b/data/y-web/Y_Boxcontrol_Menue.yhtm index e2d9a90ea..40393f4fc 100644 --- a/data/y-web/Y_Boxcontrol_Menue.yhtm +++ b/data/y-web/Y_Boxcontrol_Menue.yhtm @@ -148,6 +148,19 @@ function get_data(){

  • {=L:bc.menue.remote=}
  • + {=if-not-equal:{=var-get:boxtype=}~VU+ SOLO4K~ + {=if-not-equal:{=var-get:boxtype=}~VU+ DUO4K~ + {=if-not-equal:{=var-get:boxtype=}~VU+ ULTIMO4K~ + {=if-not-equal:{=var-get:boxtype=}~VU+ UNO4K~ + {=if-not-equal:{=var-get:boxtype=}~VU+ UNO4KSE~ +
  • + {=L:bc.menue.glcd_screenshot=} +
  • + ~=} + ~=} + ~=} + ~=} + ~=} {=if-not-equal:{=global-var-get:boxtype=}~coolstream~
  • {=if-empty:{=var-get:lcshot=}~ diff --git a/data/y-web/Y_Settings_Menue.yhtm b/data/y-web/Y_Settings_Menue.yhtm index e6b7c24d2..1a495ade9 100644 --- a/data/y-web/Y_Settings_Menue.yhtm +++ b/data/y-web/Y_Settings_Menue.yhtm @@ -84,6 +84,21 @@ function init(){ {=var-set:m_link_text={=L:set.menue.pictureviewer=}=} {=include-block:Y_Blocks.txt;management_link=}
  • + {=if-not-equal:{=var-get:boxtype=}~VU+ SOLO4K~ + {=if-not-equal:{=var-get:boxtype=}~VU+ DUO4K~ + {=if-not-equal:{=var-get:boxtype=}~VU+ ULTIMO4K~ + {=if-not-equal:{=var-get:boxtype=}~VU+ UNO4K~ + {=if-not-equal:{=var-get:boxtype=}~VU+ UNO4KSE~ +
  • + {=var-set:m_link_href=Y_Settings_glcd.yhtm=} + {=var-set:m_link_text={=L:set.menue.glcd_display=}=} + {=include-block:Y_Blocks.txt;management_link=} +
  • + ~=} + ~=} + ~=} + ~=} + ~=} {=if-not-equal:{=global-var-get:boxtype=}~coolstream~
  • {=var-set:m_link_href=Y_Settings_video_audio.yhtm=} diff --git a/data/y-web/Y_Settings_glcd.yhtm b/data/y-web/Y_Settings_glcd.yhtm new file mode 100644 index 000000000..b06da8d8e --- /dev/null +++ b/data/y-web/Y_Settings_glcd.yhtm @@ -0,0 +1,128 @@ +{=include-block:Y_Blocks.txt;management_check_top=} +{=include-block:Y_Blocks.txt;head=} + + + + + +{=var-set:wait_text={=L:save_values=}=}{=include-block:Y_Blocks.txt;snip_wait=} +
    +
    + {=var-set:help_url=Help-Settings-LCD=}{=var-set:menu=GLCD Einstellungen=}{=include-block:Y_Blocks.txt;work_menu=}
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    GLCD
    Power + AUS  + EIN +
    Invertieren + AUS  + EIN +
    Helligkeit nach dimm-Timeout + +
    Dimm-Timeout + +
    normale Helligkeit + +
    Standby Helligkeit + +
     Voreinstellung benutzen
    Anzeige-Modi
    +
    + +   +   + Hilfe +
    +
    +
    + + +{=include-block:Y_Blocks.txt;management_check_bottom=} diff --git a/data/y-web/Y_Tools_Glcd_Screenshot.yhtm b/data/y-web/Y_Tools_Glcd_Screenshot.yhtm new file mode 100644 index 000000000..6531cccdf --- /dev/null +++ b/data/y-web/Y_Tools_Glcd_Screenshot.yhtm @@ -0,0 +1,98 @@ + +{=include-block:Y_Blocks.txt;head=} + + + + + +
    +
    + {=var-set:help_url==}{=var-set:menu={=L:bc.menue.screenshot=}=}{=include-block:Y_Blocks.txt;work_menu=}
    +
    +
    +
    +
    +   +   +
    +
    +
    + {=L:filename=}: +
    +
    +
    +
    + Reload: +
    +
    +
    + +
    + + + + +
    + +
    +
    +
    + + + diff --git a/src/driver/Makefile.am b/src/driver/Makefile.am index 1ddb6b376..6dcf0ff9b 100644 --- a/src/driver/Makefile.am +++ b/src/driver/Makefile.am @@ -50,7 +50,13 @@ libneutrino_driver_a_SOURCES = \ if ENABLE_GRAPHLCD libneutrino_driver_a_SOURCES += \ - nglcd.cpp + analogclock.cpp \ + digitalclock.cpp \ + lcdclock.cpp \ + ledclock.cpp \ + simpleclock.cpp \ + weather.cpp \ + glcd.cpp endif if BOXTYPE_COOL diff --git a/src/driver/analogclock.cpp b/src/driver/analogclock.cpp new file mode 100644 index 000000000..b31965257 --- /dev/null +++ b/src/driver/analogclock.cpp @@ -0,0 +1,179 @@ +/* + analog clock - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean', + 2003 thegoodguy + + License: GPL + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include +#include +#include + +enum files +{ + ANALOG_CLOCK = 0, + ANALOG_HOUR = 1, + ANALOG_MIN = 2 +}; + +const char * const file_name[LCD_NUMBER_OF_FILES] = +{ + "analog_clock", + "analog_hour", + "analog_min" +}; + +#define NUMBER_OF_PATHS 2 +const char * const file_path[NUMBER_OF_PATHS] = +{ + LCDDIR_VAR "/oled/clock/", + DATADIR "/oled/clock/" +}; + +static std::string file[LCD_NUMBER_OF_FILES] = {""}; + +void InitAnalogClock(void) +{ + for (int i = 0; i < LCD_NUMBER_OF_FILES; i++) + { + std::string tmp_file; + for (int j = 0; j < NUMBER_OF_PATHS; j++) + { + std::string file_jpg = file_path[j]; + file_jpg += file_name[i]; + file_jpg += ".jpg"; + if (file_exists(file_jpg.c_str())) + { + tmp_file = file_jpg; + goto found; + } + std::string file_jpeg = file_path[j]; + file_jpeg += file_name[i]; + file_jpeg += ".jpeg"; + if (file_exists(file_jpeg.c_str())) + { + tmp_file = file_jpeg; + goto found; + } + std::string file_png = file_path[j]; + file_png += file_name[i]; + file_png += ".png"; + if (file_exists(file_png.c_str())) + { + tmp_file = file_png; + goto found; + } + std::string file_bmp = file_path[j]; + file_bmp += file_name[i]; + file_bmp += ".bmp"; + if (file_exists(file_bmp.c_str())) + { + tmp_file = file_bmp; + goto found; + } + std::string file_gif = file_path[j]; + file_gif += file_name[i]; + file_gif += ".gif"; + if (file_exists(file_gif.c_str())) + { + tmp_file = file_gif; + goto found; + } + } +found: + printf("[%s:%s] found file: %s\n", __file__, __func__, tmp_file.c_str()); + file[i] += std::string(tmp_file); + } + printf("[%s:%s] finish initialization\n", __file__, __func__); +} + +void RenderClock(int x, int y) +{ + cGLCD *cglcd = cGLCD::getInstance(); + cglcd->imageShow(file[ANALOG_CLOCK], x, y, 0, 0, false, true, false, false, false); +} + +void RenderHands(int hour, int min, int sec, int posx, int posy, int hour_size, int min_size, int sec_size) +{ + cGLCD *cglcd = cGLCD::getInstance(); + + int time_sec, time_min, time_hour, sec_x, sec_y, min_x, min_y, hour_x, hour_y, dia; + double pi = 3.1415926535897932384626433832795, sAngleInRad, mAngleInRad, mAngleSave, hAngleInRad; + + time_sec = sec; + time_min = min; + time_hour = hour; + + dia = 180; + + sAngleInRad = ((6 * time_sec) * (2 * pi / 360)); + sAngleInRad -= pi / 2; + + sec_x = int((dia * 0.9 * cos(sAngleInRad))); + sec_y = int((dia * 0.9 * sin(sAngleInRad))); + + mAngleInRad = ((6 * time_min) * (2 * pi / 360)); + mAngleSave = mAngleInRad; + mAngleInRad -= pi/2; + + min_x = int((dia * 0.7 * cos(mAngleInRad))); + min_y = int((dia * 0.7 * sin(mAngleInRad))); + + hAngleInRad = ((30 * time_hour) * (2 * pi / 360)); + hAngleInRad += mAngleSave/12; + hAngleInRad -= pi/2; + hour_x = int((dia * 0.5 * cos(hAngleInRad))); + hour_y = int((dia * 0.5 * sin(hAngleInRad))); + + //hour + for (int i = 0; i <= hour_size; i++) + { +#if 1 + cglcd->bitmap->DrawLine(posx-i, posy-i, posx + hour_x,posy + hour_y, GLCD::cColor::White); + cglcd->bitmap->DrawLine(posx+i, posy+i, posx + hour_x,posy + hour_y, GLCD::cColor::White); +#else + cglcd->bitmap->DrawLine(posx-i, posy-i, posx + hour_x-i,posy + hour_y-i, t.glcd_color_fg); + cglcd->bitmap->DrawLine(posx+i, posy+i, posx + hour_x+i,posy + hour_y+i, t.glcd_color_fg); +#endif + } + + //min + for (int i = 0; i <= min_size; i++) + { +#if 1 + cglcd->bitmap->DrawLine(posx-i, posy-i, posx + min_x,posy + min_y, GLCD::cColor::White); + cglcd->bitmap->DrawLine(posx+i, posy+i, posx + min_x,posy + min_y, GLCD::cColor::White); +#else + cglcd->bitmap->DrawLine(posx-i, posy-i, posx + min_x-i,posy + min_y-i, t.glcd_color_fg); + cglcd->bitmap->DrawLine(posx+i, posy+i, posx + min_x+i,posy + min_y+i, t.glcd_color_fg); +#endif + } +} + +void ShowAnalogClock(int hour, int min, int sec, int x, int y) +{ + RenderClock(0, 0); + RenderHands(hour, min, sec, x, y, 5, 3, 1); +} diff --git a/src/driver/analogclock.h b/src/driver/analogclock.h new file mode 100644 index 000000000..27eceee6a --- /dev/null +++ b/src/driver/analogclock.h @@ -0,0 +1,35 @@ +/* + LCD-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + + + License: GPL + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "glcd.h" + +#define LCDDIR_VAR "/usr/share/tuxbox/neutrino/icons" + +#define LCD_NUMBER_OF_FILES 3 + +void InitAnalogClock(); +void RenderClock(int x, int y); +void RenderHands(int hour, int min, int sec, int posx, int posy, int hour_size, int min_size, int sec_size); +void ShowAnalogClock(int hour, int min, int sec, int x, int y); diff --git a/src/driver/digitalclock.cpp b/src/driver/digitalclock.cpp new file mode 100644 index 000000000..e86b7449a --- /dev/null +++ b/src/driver/digitalclock.cpp @@ -0,0 +1,164 @@ +/* + digital clock - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean', + 2003 thegoodguy + + License: GPL + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include +#include + +#include + +enum digits +{ + TIME_ZERO = 0, + TIME_ONE = 1, + TIME_TWO = 2, + TIME_THREE = 3, + TIME_FOUR = 4, + TIME_FIVE = 5, + TIME_SIX = 6, + TIME_SEVEN = 7, + TIME_EIGHT = 8, + TIME_NINE = 9, + TIME_DOTS = 10 +}; + +const char * const digit_name[LCD_NUMBER_OF_DIGITS] = +{ + "time_zero", + "time_one", + "time_two", + "time_three", + "time_four", + "time_five", + "time_six", + "time_seven", + "time_eight", + "time_nine", + "time_dots" +}; + +#define NUMBER_OF_PATHS 2 +const char * const digit_path[NUMBER_OF_PATHS] = +{ + LCDDIR_VAR "/oled/clock/", + DATADIR "/oled/clock/" +}; + +static std::string digit[LCD_NUMBER_OF_DIGITS] = {""}; + +void InitDigitalClock(void) +{ + for (int i = 0; i < LCD_NUMBER_OF_DIGITS; i++) + { + std::string digit_file; + for (int j = 0; j < NUMBER_OF_PATHS; j++) + { + std::string file_jpg = digit_path[j]; + file_jpg += digit_name[i]; + file_jpg += ".jpg"; + if (file_exists(file_jpg.c_str())) + { + digit_file = file_jpg; + goto found; + } + std::string file_jpeg = digit_path[j]; + file_jpeg += digit_name[i]; + file_jpeg += ".jpeg"; + if (file_exists(file_jpeg.c_str())) + { + digit_file = file_jpeg; + goto found; + } + std::string file_png = digit_path[j]; + file_png += digit_name[i]; + file_png += ".png"; + if (file_exists(file_png.c_str())) + { + digit_file = file_png; + goto found; + } + std::string file_bmp = digit_path[j]; + file_bmp += digit_name[i]; + file_bmp += ".bmp"; + if (file_exists(file_bmp.c_str())) + { + digit_file = file_bmp; + goto found; + } + std::string file_gif = digit_path[j]; + file_gif += digit_name[i]; + file_gif += ".gif"; + if (file_exists(file_gif.c_str())) + { + digit_file = file_gif; + goto found; + } + } +found: + printf("[%s:%s] found file: %s\n", __file__, __func__, digit_file.c_str()); + digit[i] += std::string(digit_file); + } + printf("[%s:%s] finish initialization\n", __file__, __func__); +} + +void RenderTimeDigit(int _digit, int x, int y) +{ + cGLCD *cglcd = cGLCD::getInstance(); + if (g_settings.glcd_standby_weather) + cglcd->imageShow(digit[_digit], x, y, 0, 0, false, false, false, false, false); + else + cglcd->imageShow(digit[_digit], x, y, 0, 0, false, false, false, false, true); +} + +void RenderDots(int x, int y) +{ + cGLCD *cglcd = cGLCD::getInstance(); + if (g_settings.glcd_standby_weather) + cglcd->imageShow(digit[TIME_DOTS], x, y, 0, 0, false, false, false, true, false); + else + cglcd->imageShow(digit[TIME_DOTS], x, y, 0, 0, false, false, false, true, true); +} + +void ShowDigitalClock(int hour, int minute) +{ + cGLCD *cglcd = cGLCD::getInstance(); + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + int y = g_settings.glcd_standby_weather ? t.glcd_digital_clock_y_position : cglcd->bitmap->Height() / 2; + + int a = 10; + int b = 117; + int c = cglcd->bitmap->Width() / 2; //center dots + int d = 258; + int e = 365; + + RenderTimeDigit(hour/10, a, y); + RenderTimeDigit(hour%10, b, y); + RenderDots(c ,(g_settings.glcd_standby_weather ? (y + 35) : y)); + RenderTimeDigit(minute/10, d, y); + RenderTimeDigit(minute%10, e, y); +} diff --git a/src/driver/digitalclock.h b/src/driver/digitalclock.h new file mode 100644 index 000000000..fe1116bac --- /dev/null +++ b/src/driver/digitalclock.h @@ -0,0 +1,38 @@ +/* + LCD-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + + + License: GPL + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#pragma GCC diagnostic ignored "-Wunused-parameter" +#include +#pragma GCC diagnostic warning "-Wunused-parameter" +#include "glcd.h" + +#define LCDDIR_VAR "/usr/share/tuxbox/neutrino/icons" + +#define LCD_NUMBER_OF_DIGITS 11 + +void InitDigitalClock(); +void RenderTimeDigit(int _digit, int x, int y); +void RenderDots(int x, int y); +void ShowDigitalClock(int hour, int minute); diff --git a/src/driver/display.h b/src/driver/display.h index ea9185e85..f588ceb0a 100644 --- a/src/driver/display.h +++ b/src/driver/display.h @@ -9,5 +9,5 @@ #include #endif #ifdef ENABLE_GRAPHLCD -#include +#include #endif diff --git a/src/driver/fb_generic.cpp b/src/driver/fb_generic.cpp index ffd2bcd0b..79274dc6d 100644 --- a/src/driver/fb_generic.cpp +++ b/src/driver/fb_generic.cpp @@ -54,6 +54,8 @@ #include #include +#include + extern cVideo * videoDecoder; extern CPictureViewer * g_PicViewer; @@ -2018,3 +2020,10 @@ uint32_t CFrameBuffer::getWidth4FB_HW_ACC(const uint32_t /*x*/, const uint32_t w { return w; } + +void CFrameBuffer::blit() +{ +#ifdef ENABLE_GRAPHLCD + cGLCD::Blit(); +#endif +} diff --git a/src/driver/fb_generic.h b/src/driver/fb_generic.h index a35c99dda..c6e383fc2 100644 --- a/src/driver/fb_generic.h +++ b/src/driver/fb_generic.h @@ -346,7 +346,7 @@ class CFrameBuffer : public sigc::trackable void setFbArea(int element, int _x=0, int _y=0, int _dx=0, int _dy=0); void fbNoCheck(bool noCheck) { fb_no_check = noCheck; } void doPaintMuteIcon(bool mode) { do_paint_mute_icon = mode; } - void blit(void) {} + void blit(); sigc::signal OnAfterSetPallette; sigc::signal OnFallbackShowFrame; const char *fb_name; diff --git a/src/driver/glcd.cpp b/src/driver/glcd.cpp new file mode 100644 index 000000000..8e7ef9dbc --- /dev/null +++ b/src/driver/glcd.cpp @@ -0,0 +1,1727 @@ +/* + Neutrino graphlcd daemon thread + + (C) 2012-2014 by martii + + + License: GPL + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "analogclock.h" +#include "digitalclock.h" +#include "lcdclock.h" +#include "ledclock.h" +#include "simpleclock.h" +#include "weather.h" + +#include "zlib.h" +#include "png.h" +#include "jpeglib.h" + +#define LCD_ICONSDIR "/share/lcd/icons/" +#define ICONSEXT ".png" + +static const char * kDefaultConfigFile = "/etc/graphlcd.conf"; +static cGLCD *cglcd = NULL; + +extern CRemoteControl *g_RemoteControl; +extern CPictureViewer * g_PicViewer; + +cGLCD::cGLCD() +{ + lcd = NULL; + Logo = ""; + Channel = "Neutrino"; + Epg = std::string(g_info.hw_caps->boxvendor) + " " + std::string(g_info.hw_caps->boxname); + + sem_init(&sem, 0, 1); + + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP); + pthread_mutex_init(&mutex, &attr); + + channelLocked = false; + timeLocked = false; + durationLocked = false; + startLocked = false; + endLocked = false; + recLocked = false; + muteLocked = false; + tsLocked = false; + ecmLocked = false; + timerLocked = false; + ddLocked = false; + txtLocked = false; + subLocked = false; + camLocked = false; + doRescan = false; + doStandby = false; + doStandbyTime = false; + doShowVolume = false; + doShowLcdIcon = false; + doSuspend = false; + doExit = false; + doMirrorOSD = false; + fontsize_channel = 0; + fontsize_epg = 0; + fontsize_time = 0; + fontsize_duration = 0; + fontsize_start = 0; + fontsize_end = 0; + fontsize_smalltext = 0; + fonts_initialized = false; + ismediaplayer = false; + doScrollChannel = false; + doScrollEpg = false; + percent_channel = 0; + percent_time = 0; + percent_duration = 0; + percent_start = 0; + percent_end = 0; + percent_smalltext = 0; + percent_epg = 0; + percent_bar = 0; + percent_logo = 0; + power_state = 1; + Scale = 0; + bitmap = NULL; + blitFlag = true; + timeout_cnt = 0; + locked_countdown = false; + time_thread_started = false; + + cglcd = this; + + if (!g_settings.glcd_enable) + doSuspend = true; + + if (pthread_create (&thrGLCD, 0, cGLCD::Run, this) != 0 ) + fprintf(stderr, "ERROR: pthread_create(cGLCD::Init)\n"); + + if (pthread_create (&thrTimeThread, 0, cGLCD::TimeThread, this) != 0 ) + fprintf(stderr, "ERROR: pthread_create(cGLCD::TimeThread)\n"); + + InitAnalogClock(); + InitDigitalClock(); + InitLcdClock(); + InitLedClock(); + InitSimpleClock(); + InitWeather(); + + Update(); +} + +void cGLCD::Lock(void) +{ + if (cglcd) + { + pthread_mutex_lock(&cglcd->mutex); + } +} + +void cGLCD::Unlock(void) +{ + if (cglcd) + { + pthread_mutex_unlock(&cglcd->mutex); + } +} + +cGLCD::~cGLCD() +{ + Suspend(); + cglcd = NULL; + if (lcd) + { + lcd->DeInit(); + delete lcd; + } + sem_destroy(&sem); + pthread_mutex_destroy(&mutex); +} + +cGLCD *cGLCD::getInstance() +{ + if (!cglcd) + cglcd = new cGLCD; + return cglcd; +} + +uint32_t cGLCD::ColorConvert3to1(uint32_t red, uint32_t green, uint32_t blue) +{ + unsigned int color_red_tmp = (static_cast(red) * 2.55) + 1; + unsigned int color_green_tmp = (static_cast(green) * 2.55) + 1; + unsigned int color_blue_tmp = (static_cast(blue) * 2.55) + 1; + + uint32_t color = 0xff; color <<= 8; + color |= color_red_tmp; color <<= 8; + color |= color_green_tmp; color <<= 8; + color |= color_blue_tmp; + + return color; +} + +void cGLCD::Exec() +{ + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + + if (!lcd) + return; + + bitmap->Clear(ColorConvert3to1(t.glcd_color_bg_red, t.glcd_color_bg_green, t.glcd_color_bg_blue)); + + if (Channel == "Neutrino") + { + if (g_settings.glcd_show_logo) + { + if (imageShow(DATADIR "/neutrino/icons/start.jpg", 0, 0, 0, 0, false, true, true, false, false)) + { + GLCD::cFont font_tmp; + + int fw = font_epg.Width(Epg); + font_tmp.LoadFT2(t.glcd_font, "UTF-8", fontsize_epg * (bitmap->Width() - 4) / fw); + fw = font_tmp.Width(Epg); + + drawText(std::max(2,(bitmap->Width() - 4 - fw)/2), + 10 * bitmap->Height()/100, bitmap->Width() - 4, fw, Epg, + &font_tmp, ColorConvert3to1(t.glcd_color_fg_red, t.glcd_color_fg_green, t.glcd_color_fg_blue), GLCD::cColor::Transparent, true, 0, ALIGN_NONE); + + lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height()); + lcd->Refresh(true); + } + } else { + cglcd->bitmap->Clear(ColorConvert3to1(t.glcd_color_bg_red, t.glcd_color_bg_green, t.glcd_color_bg_blue)); + cglcd->lcd->Refresh(true); + } + return; + } + + if (doStandbyTime) + { + std::string Time; + if (g_settings.glcd_time_in_standby == 5) + { + ShowAnalogClock(tm->tm_hour, tm->tm_min, tm->tm_sec, bitmap->Width()/2, bitmap->Height()/2); + } + else if (g_settings.glcd_time_in_standby == 4) + { + ShowDigitalClock(tm->tm_hour, tm->tm_min); + } + else if (g_settings.glcd_time_in_standby == 3) + { + Time = strftime("%H:%M", tm); + ShowLcdClock(Time); + } + else if (g_settings.glcd_time_in_standby == 2) + { + Time = strftime("%H:%M", tm); + ShowLedClock(Time); + } + else + { + Time = strftime("%H:%M", tm); + ShowSimpleClock(Time); + } + if (g_settings.glcd_standby_weather == 1 && g_settings.glcd_time_in_standby != 5) + { + ShowWeather(true); + } + lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height()); + lcd->Refresh(false); + return; + } + + if (t.glcd_background != "") + imageShow(t.glcd_background, 0, 0, 0, 0, false, true, true, false, false); + + if (t.glcd_show_weather) + ShowWeather(false); + + switch (CAudioPlayer::getInstance()->getState()) + { + case CBaseDec::REV: + ismediaplayer = true; + Logo = ICONSDIR "/" NEUTRINO_ICON_REW ICONSEXT; + break; + case CBaseDec::FF: + ismediaplayer = true; + Logo = ICONSDIR "/" NEUTRINO_ICON_FF ICONSEXT; + break; + case CBaseDec::PAUSE: + ismediaplayer = true; + Logo = ICONSDIR "/" NEUTRINO_ICON_PAUSE ICONSEXT; + break; + case CBaseDec::PLAY: + ismediaplayer = true; + Logo = ICONSDIR "/" NEUTRINO_ICON_PLAY ICONSEXT; + break; + default: + ismediaplayer = false; + ; + } + + switch (CMoviePlayerGui::getInstance().getState()) + { + case CMoviePlayerGui::REW: + ismediaplayer = true; + Logo = ICONSDIR "/" NEUTRINO_ICON_REW ICONSEXT; + break; + case CMoviePlayerGui::FF: + ismediaplayer = true; + Logo = ICONSDIR "/" NEUTRINO_ICON_FF ICONSEXT; + break; + case CMoviePlayerGui::PAUSE: + ismediaplayer = true; + Logo = ICONSDIR "/" NEUTRINO_ICON_PAUSE ICONSEXT; + break; + case CMoviePlayerGui::PLAY: + ismediaplayer = true; + Logo = ICONSDIR "/" NEUTRINO_ICON_PLAY ICONSEXT; + break; + default: + ismediaplayer = false; + ; + } + + int icon_start_width = 0, icon_start_height = 0; + g_PicViewer->getSize(Logo.c_str(), &icon_start_width, &icon_start_height); + + if (g_settings.glcd_show_logo && percent_logo && + showImage(channel_id, Channel, 0, t.glcd_channel_x_position, t.glcd_channel_y_position, percent_logo * bitmap->Height()/100, true, false)) { + doScrollChannel = false; + scrollChannelSkip = 0; + } else if (percent_logo && icon_start_width && icon_start_height && + doShowLcdIcon && showImage(Logo, icon_start_width, icon_start_height, t.glcd_channel_x_position, t.glcd_channel_y_position, bitmap->Width() - 4, percent_logo * bitmap->Height()/100, true, false)) { + doScrollChannel = false; + scrollChannelSkip = 0; + } else if (percent_channel) { + if (ChannelWidth) { + if (scrollChannelForward) { + if (ChannelWidth - scrollChannelSkip < bitmap->Width() - 4) + scrollChannelForward = false; + } else if (scrollChannelSkip <= 0) { + scrollChannelSkip = 0; + doScrollChannel = false; + } + + drawText(t.glcd_channel_x_position + scrollChannelOffset, + t.glcd_channel_y_position, bitmap->Width() - 4, ChannelWidth, Channel, + &font_channel, ColorConvert3to1(t.glcd_color_fg_red, t.glcd_color_fg_green, t.glcd_color_fg_blue), GLCD::cColor::Transparent, true, scrollChannelSkip, t.glcd_align_channel); + + if (scrollChannelOffset > 0) + scrollChannelOffset -= g_settings.glcd_scroll_speed; + + if (scrollChannelOffset < 0) + scrollChannelOffset = 0; + + if (scrollChannelOffset == 0) { + if (scrollChannelForward) + scrollChannelSkip += g_settings.glcd_scroll_speed; + else + scrollChannelSkip -= g_settings.glcd_scroll_speed; + } + } + } + + if (percent_epg) + { + if (EpgWidth) + { + if (scrollEpgForward) { + if (EpgWidth - scrollEpgSkip < bitmap->Width() - 4) + scrollEpgForward = false; + } else if (scrollEpgSkip <= 0) { + scrollEpgSkip = 0; + doScrollEpg = false; + } + + drawText(t.glcd_epg_x_position + scrollEpgOffset, + t.glcd_epg_y_position, bitmap->Width() - 4, EpgWidth, Epg, + &font_epg, ColorConvert3to1(t.glcd_color_fg_red, t.glcd_color_fg_green, t.glcd_color_fg_blue), GLCD::cColor::Transparent, true, scrollEpgSkip, t.glcd_align_epg); + + if (scrollEpgOffset > 0) + scrollEpgOffset -= g_settings.glcd_scroll_speed; + + if (scrollEpgOffset < 0) + scrollEpgOffset = 0; + + if (scrollEpgOffset == 0) { + if (scrollEpgForward) + scrollEpgSkip += g_settings.glcd_scroll_speed; + else + scrollEpgSkip -= g_settings.glcd_scroll_speed; + } + } + } + + if (percent_bar && t.glcd_show_progressbar) + { + int tmp_pos = 0; + tmp_pos = t.glcd_bar_y_position; + + int bar_top = 0; + int bar_bottom = 0; + + bar_top = tmp_pos; + bar_bottom = tmp_pos + t.glcd_percent_bar; + + showProgressBarBorder(t.glcd_bar_x_position, bar_top, t.glcd_bar_width, bar_bottom, Scale, GLCD::cColor::White, ColorConvert3to1(t.glcd_color_bar_red, t.glcd_color_bar_green, t.glcd_color_bar_blue)); + } + + if (percent_time && t.glcd_show_time) + { + Lock(); + Time = strftime("%H:%M", tm); + TimeWidth = font_time.Width(Time); + Unlock(); + + drawText(t.glcd_time_x_position, + t.glcd_time_y_position, bitmap->Width() - 1, TimeWidth, Time, + &font_time, ColorConvert3to1(t.glcd_color_fg_red, t.glcd_color_fg_green, t.glcd_color_fg_blue), GLCD::cColor::Transparent, true, 0, t.glcd_align_time); + } + + if (percent_duration && t.glcd_show_duration) + { + + Lock(); + Duration = stagingDuration; + DurationWidth = font_duration.Width(Duration); + Unlock(); + + drawText(t.glcd_duration_x_position, + t.glcd_duration_y_position, bitmap->Width() - 1, DurationWidth, Duration, + &font_duration, ColorConvert3to1(t.glcd_color_fg_red, t.glcd_color_fg_green, t.glcd_color_fg_blue), GLCD::cColor::Transparent, true, 0, t.glcd_align_duration); + } + + if (percent_start && t.glcd_show_start) + { + + Lock(); + Start = stagingStart; + StartWidth = font_start.Width(Start); + Unlock(); + + drawText(t.glcd_start_x_position, + t.glcd_start_y_position, bitmap->Width() - 1, StartWidth, Start, + &font_start, ColorConvert3to1(t.glcd_color_fg_red, t.glcd_color_fg_green, t.glcd_color_fg_blue), GLCD::cColor::Transparent, true, 0, t.glcd_align_start); + } + + if (percent_end && t.glcd_show_end) + { + Lock(); + End = stagingEnd; + EndWidth = font_end.Width(End); + Unlock(); + + drawText(t.glcd_end_x_position, + t.glcd_end_y_position, bitmap->Width() - 1, EndWidth, End, + &font_end, ColorConvert3to1(t.glcd_color_fg_red, t.glcd_color_fg_green, t.glcd_color_fg_blue), GLCD::cColor::Transparent, true, 0, t.glcd_align_end); + } + + if (percent_smalltext && !doStandby) { + Lock(); + SmalltextWidth = font_smalltext.Width(Smalltext); + Unlock(); + + if (access("/tmp/ecm.info", F_OK) == 0) + { + struct stat buf; + stat("/tmp/ecm.info", &buf); + if (buf.st_size > 0) + ecmLocked = true; + else + ecmLocked = false; + } + + if (recLocked) { + drawText(t.glcd_rec_icon_x_position, t.glcd_smalltext_y_position, + bitmap->Width() - 1, SmalltextWidth, "rec", &font_smalltext, GLCD::cColor::Red, + GLCD::cColor::Transparent, true, 0, 0); + } else { + drawText(t.glcd_rec_icon_x_position, t.glcd_smalltext_y_position, + bitmap->Width() - 1, SmalltextWidth, "rec", &font_smalltext, GLCD::cColor::Gray, + GLCD::cColor::Transparent, true, 0, 0); + } + + if (muteLocked) { + drawText(t.glcd_mute_icon_x_position, t.glcd_smalltext_y_position, + bitmap->Width() - 1, SmalltextWidth, "mute", &font_smalltext, GLCD::cColor::Green, + GLCD::cColor::Transparent, true, 0, 0); + } else { + drawText(t.glcd_mute_icon_x_position, t.glcd_smalltext_y_position, + bitmap->Width() - 1, SmalltextWidth, "mute", &font_smalltext, GLCD::cColor::Gray, + GLCD::cColor::Transparent, true, 0, 0); + } + + if (tsLocked) { + drawText(t.glcd_ts_icon_x_position, t.glcd_smalltext_y_position, + bitmap->Width() - 1, SmalltextWidth, "ts", &font_smalltext, GLCD::cColor::Red, + GLCD::cColor::Transparent, true, 0, 0); + } else { + drawText(t.glcd_ts_icon_x_position, t.glcd_smalltext_y_position, + bitmap->Width() - 1, SmalltextWidth, "ts", &font_smalltext, GLCD::cColor::Gray, + GLCD::cColor::Transparent, true, 0, 0); + } + + if (ecmLocked) { + drawText(t.glcd_ecm_icon_x_position, t.glcd_smalltext_y_position, + bitmap->Width() - 1, SmalltextWidth, "ecm", &font_smalltext, GLCD::cColor::Green, + GLCD::cColor::Transparent, true, 0, 0); + } else { + drawText(t.glcd_ecm_icon_x_position, t.glcd_smalltext_y_position, + bitmap->Width() - 1, SmalltextWidth, "ecm", &font_smalltext, GLCD::cColor::Gray, + GLCD::cColor::Transparent, true, 0, 0); + } + + if (timerLocked) { + drawText(t.glcd_timer_icon_x_position, t.glcd_smalltext_y_position, + bitmap->Width() - 1, SmalltextWidth, "timer", &font_smalltext, GLCD::cColor::Green, + GLCD::cColor::Transparent, true, 0, 0); + } else { + drawText(t.glcd_timer_icon_x_position, t.glcd_smalltext_y_position, + bitmap->Width() - 1, SmalltextWidth, "timer", &font_smalltext, GLCD::cColor::Gray, + GLCD::cColor::Transparent, true, 0, 0); + } + + if (ddLocked) { + drawText(t.glcd_dd_icon_x_position, t.glcd_smalltext_y_position, + bitmap->Width() - 1, SmalltextWidth, "dd", &font_smalltext, GLCD::cColor::Green, + GLCD::cColor::Transparent, true, 0, 0); + } else { + drawText(t.glcd_dd_icon_x_position, t.glcd_smalltext_y_position, + bitmap->Width() - 1, SmalltextWidth, "dd", &font_smalltext, GLCD::cColor::Gray, + GLCD::cColor::Transparent, true, 0, 0); + } + + if (ismediaplayer) { + if (subLocked) { + drawText(t.glcd_txt_icon_x_position, t.glcd_smalltext_y_position, + bitmap->Width() - 1, SmalltextWidth, "sub", &font_smalltext, GLCD::cColor::Green, + GLCD::cColor::Transparent, true, 0, 0); + } else { + drawText(t.glcd_txt_icon_x_position, t.glcd_smalltext_y_position, + bitmap->Width() - 1, SmalltextWidth, "sub", &font_smalltext, GLCD::cColor::Gray, + GLCD::cColor::Transparent, true, 0, 0); + } + } else { + if (txtLocked) { + drawText(t.glcd_txt_icon_x_position, t.glcd_smalltext_y_position, + bitmap->Width() - 1, SmalltextWidth, "txt", &font_smalltext, GLCD::cColor::Green, + GLCD::cColor::Transparent, true, 0, 0); + } else { + drawText(t.glcd_txt_icon_x_position, t.glcd_smalltext_y_position, + bitmap->Width() - 1, SmalltextWidth, "txt", &font_smalltext, GLCD::cColor::Gray, + GLCD::cColor::Transparent, true, 0, 0); + } + } + + if (camLocked) { + drawText(t.glcd_cam_icon_x_position, t.glcd_smalltext_y_position, + bitmap->Width() - 1, SmalltextWidth, "cam", &font_smalltext, GLCD::cColor::Green, + GLCD::cColor::Transparent, true, 0, 0); + } else { + drawText(t.glcd_cam_icon_x_position, t.glcd_smalltext_y_position, + bitmap->Width() - 1, SmalltextWidth, "cam", &font_smalltext, GLCD::cColor::Gray, + GLCD::cColor::Transparent, true, 0, 0); + } + } + + lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height()); + lcd->Refresh(false); +} + +void cGLCD::updateFonts() +{ + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + + percent_logo = std::min(t.glcd_percent_logo, 100); + percent_channel = std::min(t.glcd_percent_channel, 100); + percent_epg = std::min(t.glcd_percent_epg, 100); + percent_bar = std::min(t.glcd_percent_bar, 100); + percent_time = std::min(t.glcd_percent_time, 100); + percent_duration = std::min(t.glcd_percent_duration, 100); + percent_start = std::min(t.glcd_percent_start, 100); + percent_end = std::min(t.glcd_percent_end, 100); + percent_smalltext = std::min(t.glcd_percent_smalltext, 100); + + // calculate height + int fontsize_channel_new = percent_channel * cglcd->lcd->Height() / 100; + int fontsize_epg_new = percent_epg * cglcd->lcd->Height() / 100; + int fontsize_time_new = percent_time * cglcd->lcd->Height() / 100; + int fontsize_duration_new = percent_duration * cglcd->lcd->Height() / 100; + int fontsize_start_new = percent_start * cglcd->lcd->Height() / 100; + int fontsize_end_new = percent_end * cglcd->lcd->Height() / 100; + int fontsize_smalltext_new = percent_smalltext * cglcd->lcd->Height() / 100; + + if (!fonts_initialized || (fontsize_channel_new != fontsize_channel)) { + fontsize_channel = fontsize_channel_new; + if (!font_channel.LoadFT2(t.glcd_font, "UTF-8", fontsize_channel)) { + t.glcd_font = FONTDIR "/neutrino.ttf"; + font_channel.LoadFT2(t.glcd_font, "UTF-8", fontsize_channel); + } + } + if (!fonts_initialized || (fontsize_epg_new != fontsize_epg)) { + fontsize_epg = fontsize_epg_new; + if (!font_epg.LoadFT2(t.glcd_font, "UTF-8", fontsize_epg)) { + t.glcd_font = FONTDIR "/neutrino.ttf"; + font_epg.LoadFT2(t.glcd_font, "UTF-8", fontsize_epg); + } + } + if (!fonts_initialized || (fontsize_time_new != fontsize_time)) { + fontsize_time = fontsize_time_new; + if (!font_time.LoadFT2(t.glcd_font, "UTF-8", fontsize_time)) { + t.glcd_font = FONTDIR "/neutrino.ttf"; + font_time.LoadFT2(t.glcd_font, "UTF-8", fontsize_time); + } + } + + if (!fonts_initialized || (fontsize_duration_new != fontsize_duration)) { + fontsize_duration = fontsize_duration_new; + if (!font_duration.LoadFT2(t.glcd_font, "UTF-8", fontsize_duration)) { + t.glcd_font = FONTDIR "/neutrino.ttf"; + font_duration.LoadFT2(t.glcd_font, "UTF-8", fontsize_duration); + } + } + + if (!fonts_initialized || (fontsize_start_new != fontsize_start)) { + fontsize_start = fontsize_start_new; + if (!font_start.LoadFT2(t.glcd_font, "UTF-8", fontsize_start)) { + t.glcd_font = FONTDIR "/neutrino.ttf"; + font_start.LoadFT2(t.glcd_font, "UTF-8", fontsize_start); + } + } + + if (!fonts_initialized || (fontsize_end_new != fontsize_end)) { + fontsize_end = fontsize_end_new; + if (!font_end.LoadFT2(t.glcd_font, "UTF-8", fontsize_end)) { + t.glcd_font = FONTDIR "/neutrino.ttf"; + font_end.LoadFT2(t.glcd_font, "UTF-8", fontsize_end); + } + } + + if (!fonts_initialized || (fontsize_smalltext_new != fontsize_smalltext)) { + fontsize_smalltext = fontsize_smalltext_new; + if (!font_smalltext.LoadFT2(/*t.glcd_font*/FONTDIR "/lcd.ttf", "UTF-8", fontsize_smalltext)) { + t.glcd_font = FONTDIR "/lcd.ttf"; + font_smalltext.LoadFT2(t.glcd_font, "UTF-8", fontsize_smalltext); + } + } + + fonts_initialized = true; +} + +bool cGLCD::getBoundingBox(uint32_t *buffer, int width, int height, int &bb_x, int &bb_y, int &bb_w, int &bb_h) +{ + if (!width || !height) { + bb_x = bb_y = bb_w = bb_h = 0; + return false; + } + + int y_min = height; + uint32_t *b = buffer; + for (int y = 0; y < height; y++) + for (int x = 0; x < width; x++, b++) + if (*b) { + y_min = y; + goto out1; + } +out1: + int y_max = y_min; + b = buffer + height * width - 1; + for (int y = height - 1; y_min < y; y--) + for (int x = 0; x < width; x++, b--) + if (*b) { + y_max = y; + goto out2; + } +out2: + int x_min = width; + for (int x = 0; x < width; x++) { + b = buffer + x + y_min * width; + for (int y = y_min; y < y_max; y++, b += width) + if (*b) { + x_min = x; + goto out3; + } + } +out3: + int x_max = x_min; + for (int x = width - 1; x_min < x; x--) { + b = buffer + x + y_min * width; + for (int y = y_min; y < y_max; y++, b += width) + if (*b) { + x_max = x; + goto out4; + } + } +out4: + bb_x = x_min; + bb_y = y_min; + bb_w = 1 + x_max - x_min; + bb_h = 1 + y_max - y_min; + + if (bb_x < 0) + bb_x = 0; + if (bb_y < 0) + bb_y = 0; + + return true; +} + +void* cGLCD::Run(void *arg) +{ + cGLCD *me = (cGLCD *)arg; + me->Run(); + pthread_exit(NULL); +} + +void cGLCD::CountDown() +{ + if (timeout_cnt > 0) + { + timeout_cnt--; + if (timeout_cnt == 0) + { + UpdateBrightness(); + cglcd->locked_countdown = false; + } + } +} + +void cGLCD::WakeUp() +{ + int tmp = atoi(g_settings.glcd_brightness_dim_time.c_str()); + if (tmp > 0) + { + timeout_cnt = (unsigned int)tmp; + UpdateBrightness(); + cglcd->locked_countdown = true; + } +} + +void* cGLCD::TimeThread(void *p) +{ + set_threadname("cGLCD:Time"); + ((cGLCD *)p)->time_thread_started = true; + while (((cGLCD *)p)->time_thread_started) + { + sleep(1); + if ((cglcd->locked_countdown == true || cglcd->channelLocked == true || cglcd->timeLocked == true || + cglcd->durationLocked == true || cglcd->startLocked == true || cglcd->endLocked == true || + cglcd->recLocked == true || cglcd->muteLocked == true || cglcd->tsLocked == true || + cglcd->ecmLocked == true || cglcd->timerLocked == true || cglcd->ddLocked == true || + cglcd->txtLocked == true || cglcd->camLocked == true || + cglcd->doShowVolume == true || cglcd->doMirrorOSD == true) && !cglcd->doExit) + { + cGLCD::getInstance()->CountDown(); + } + } + return NULL; +} + +void cGLCD::Run(void) +{ + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + + set_threadname("cGLCD::Run"); + + if (GLCD::Config.Load(kDefaultConfigFile) == false) + { + fprintf(stderr, "Error loading config file!\n"); + return; + } + if ((GLCD::Config.driverConfigs.size() < 1)) + { + fprintf(stderr, "No driver config found!\n"); + return; + } + + struct timespec ts; + + CSectionsdClient::CurrentNextInfo info_CurrentNext; + channel_id = -1; + info_CurrentNext.current_zeit.startzeit = 0; + info_CurrentNext.current_zeit.dauer = 0; + info_CurrentNext.flags = 0; + + fonts_initialized = false; + bool broken = false; + + do + { + if (broken) + { +#ifdef GLCD_DEBUG + fprintf(stderr, "No graphlcd display found ... sleeping for 30 seconds\n"); +#endif + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 30; + sem_timedwait(&sem, &ts); + broken = false; + if (doExit) + break; + if (!g_settings.glcd_enable) + continue; + } else + while ((doSuspend || doStandby || !g_settings.glcd_enable) && !doExit) + sem_wait(&sem); + + if (doExit) + break; + + int warmUp = 10; + lcd = GLCD::CreateDriver(GLCD::Config.driverConfigs[0].id, &GLCD::Config.driverConfigs[0]); + if (!lcd) { +#ifdef GLCD_DEBUG + fprintf(stderr, "CreateDriver failed.\n"); +#endif + broken = true; + continue; + } +#ifdef GLCD_DEBUG + fprintf(stderr, "CreateDriver succeeded.\n"); +#endif + if (lcd->Init()) + { + delete lcd; + lcd = NULL; +#ifdef GLCD_DEBUG + fprintf(stderr, "LCD init failed.\n"); +#endif + broken = true; + continue; + } +#ifdef GLCD_DEBUG + fprintf(stderr, "LCD init succeeded.\n"); +#endif + lcd->SetBrightness(0); + + if (!bitmap) + bitmap = new GLCD::cBitmap(lcd->Width(), lcd->Height(), ColorConvert3to1(t.glcd_color_bg_red, t.glcd_color_bg_green, t.glcd_color_bg_blue)); + + UpdateBrightness(); + Update(); + + doMirrorOSD = false; + + while ((!doSuspend && !doStandby) && !doExit && g_settings.glcd_enable) + { + if (doMirrorOSD && !doStandbyTime) + { + if (blitFlag) + { + blitFlag = false; + bitmap->Clear(GLCD::cColor::Black); + ts.tv_sec = 0; // don't wait + static CFrameBuffer* fb = CFrameBuffer::getInstance(); + static int fb_width = fb->getScreenWidth(true); + static int fb_height = fb->getScreenHeight(true); + static uint32_t *fbp = fb->getFrameBufferPointer(); + int lcd_width = bitmap->Width(); + int lcd_height = bitmap->Height(); +#if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUULTIMO4K || BOXMODEL_VUUNO4KSE || BOXMODEL_VUUNO4K + unsigned int fb_stride = fb->getStride()/4; + if (!showImage(fbp, fb_stride, fb_height, 0, 0, lcd_width, lcd_height, false, true)) + { +#else + if (!showImage(fbp, fb_width, fb_height, 0, 0, lcd_width, lcd_height, false, true)) + { +#endif + usleep(500000); + } + else + { + lcd->SetScreen(bitmap->Data(), lcd_width, lcd_height); + lcd->Refresh(false); + } + } + else + usleep(100000); + continue; + } + + if (g_settings.glcd_mirror_video && !doStandbyTime) + { +#if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUULTIMO4K || BOXMODEL_VUUNO4KSE || BOXMODEL_VUUNO4K + lcd->SetMirrorVideo(true); +#else + char ws[10]; + snprintf(ws, sizeof(ws), "%d", bitmap->Width()); + const char *bmpShot = "/tmp/glcd-video.bmp"; + my_system(4, "/bin/grab", "-vr", ws, bmpShot); + int bw = 0, bh = 0; + g_PicViewer->getSize(bmpShot, &bw, &bh); + if (bw > 0 && bh > 0) + { + int lcd_width = bitmap->Width(); + int lcd_height = bitmap->Height(); + if (!showImage(bmpShot, (uint32_t) bw, (uint32_t) bh, 0, 0, (uint32_t) lcd_width, (uint32_t) lcd_height, false, true)) + usleep(1000000); + else + { + lcd->SetScreen(bitmap->Data(), lcd_width, lcd_height); + lcd->Refresh(false); + } + } + else + usleep(1000000); + continue; +#endif + } +#if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUULTIMO4K || BOXMODEL_VUUNO4KSE || BOXMODEL_VUUNO4K + else + lcd->SetMirrorVideo(false); +#endif + + clock_gettime(CLOCK_REALTIME, &ts); + tm = localtime(&ts.tv_sec); + updateFonts(); + Exec(); + clock_gettime(CLOCK_REALTIME, &ts); + tm = localtime(&ts.tv_sec); + if (warmUp > 0) + { + ts.tv_sec += 1; + warmUp--; + } + else + { + ts.tv_sec += 60 - tm->tm_sec; + ts.tv_nsec = 0; + } + + if (!doScrollChannel && !doScrollEpg) + sem_timedwait(&sem, &ts); + + while(!sem_trywait(&sem)); + + if(doRescan || doSuspend || doStandby || doExit) + break; + + if (doShowVolume) + { + if (ismediaplayer) + { + Channel = ""; + if (Epg.compare(g_Locale->getText(LOCALE_GLCD_VOLUME))) + { + Epg = g_Locale->getText(LOCALE_GLCD_VOLUME); + EpgWidth = font_epg.Width(Epg); + doScrollEpg = EpgWidth > bitmap->Width() - 4; + scrollEpgSkip = 0; + scrollEpgForward = true; + if (doScrollEpg) { + scrollEpgOffset = bitmap->Width()/g_settings.glcd_scroll_speed; + EpgWidth += scrollEpgOffset; + } + else + scrollEpgOffset = 0; + } + ChannelWidth = 0; + scrollChannelSkip = 0; + scrollChannelForward = true; + Scale = g_settings.current_volume; + //epg_id = -1; + } else { + Epg = ""; + if (Channel.compare(g_Locale->getText(LOCALE_GLCD_VOLUME))) + { + Channel = g_Locale->getText(LOCALE_GLCD_VOLUME); + ChannelWidth = font_channel.Width(Channel); + doScrollChannel = ChannelWidth > bitmap->Width() - 4; + scrollChannelSkip = 0; + scrollChannelForward = true; + if (doScrollChannel) { + scrollChannelOffset = bitmap->Width()/g_settings.glcd_scroll_speed; + ChannelWidth += scrollChannelOffset; + } + else + scrollChannelOffset = 0; + } + EpgWidth = 0; + scrollEpgSkip = 0; + scrollEpgForward = true; + Scale = g_settings.current_volume; + channel_id = -1; + } + } + else if (channelLocked) + { + Lock(); + if (Epg.compare(stagingEpg)) + { + Epg = stagingEpg; + EpgWidth = font_epg.Width(Epg); + doScrollEpg = EpgWidth > bitmap->Width() - 4; + scrollEpgSkip = 0; + scrollEpgForward = true; + if (doScrollEpg) + { + scrollEpgOffset = bitmap->Width()/g_settings.glcd_scroll_speed; + EpgWidth += scrollEpgOffset; + } + else + scrollChannelOffset = 0; + } + if (Channel.compare(stagingChannel)) + { + Channel = stagingChannel; + ChannelWidth = font_channel.Width(Channel); + doScrollChannel = ChannelWidth > bitmap->Width() - 4; + scrollChannelSkip = 0; + scrollChannelForward = true; + if (doScrollChannel) + { + scrollChannelOffset = bitmap->Width()/g_settings.glcd_scroll_speed; + ChannelWidth += scrollChannelOffset; + } + else + scrollChannelOffset = 0; + } + channel_id = -1; + Unlock(); + } + else + { + CChannelList *channelList = CNeutrinoApp::getInstance ()->channelList; + if (!channelList) + continue; + t_channel_id new_channel_id = channelList->getActiveChannel_ChannelID(); + if (!new_channel_id) + continue; + + if ((new_channel_id != channel_id)) + { + Channel = channelList->getActiveChannelName (); + ChannelWidth = font_channel.Width(Channel); + Epg = ""; + EpgWidth = 0; + Scale = 0; + doScrollEpg = false; + doScrollChannel = ChannelWidth > bitmap->Width() - 4; + scrollChannelForward = true; + scrollChannelSkip = 0; + if (doScrollChannel) { + scrollChannelOffset = bitmap->Width()/g_settings.glcd_scroll_speed; + ChannelWidth += scrollChannelOffset; + } + else + scrollChannelOffset = 0; + warmUp = 10; + info_CurrentNext.current_name = ""; + info_CurrentNext.current_zeit.dauer = 0; + } + + CEitManager::getInstance()->getCurrentNextServiceKey(channel_id & 0xFFFFFFFFFFFFULL, info_CurrentNext); + channel_id = new_channel_id; + + if (info_CurrentNext.current_name.compare(Epg)) + { + Epg = info_CurrentNext.current_name; + EpgWidth = font_epg.Width(Epg); + doScrollEpg = EpgWidth > bitmap->Width() - 4; + scrollEpgForward = true; + scrollEpgSkip = 0; + if (doScrollEpg) + { + scrollEpgOffset = bitmap->Width()/g_settings.glcd_scroll_speed; + EpgWidth += scrollEpgOffset; + } else + scrollEpgOffset = 0; + } + + if (CSectionsdClient::epgflags::has_current) + { + if ((info_CurrentNext.current_zeit.dauer > 0) && (info_CurrentNext.current_zeit.dauer < 86400)) + { + Scale = (ts.tv_sec - info_CurrentNext.current_zeit.startzeit) * 100 / info_CurrentNext.current_zeit.dauer; + char tmp_duration[6] = {0}; + int total = info_CurrentNext.current_zeit.dauer / 60; + int done = (abs(time(NULL) - info_CurrentNext.current_zeit.startzeit) + 30) / 60; + int todo = total - done; + if ((time(NULL) < info_CurrentNext.current_zeit.startzeit) && todo >= 0) + { + done = 0; + todo = info_CurrentNext.current_zeit.dauer / 60; + } + snprintf(tmp_duration, sizeof(tmp_duration), "%d/%d", done, total); + Duration = tmp_duration; + } + if (Scale > 100) + Scale = 100; + else if (Scale < 0) + Scale = 0; + char tmp_start[6] = {0}; + tm = localtime(&info_CurrentNext.current_zeit.startzeit); + snprintf(tmp_start, sizeof(tmp_start), "%02d:%02d", tm->tm_hour, tm->tm_min); + Start = tmp_start; + } + + if (CSectionsdClient::epgflags::has_next) + { + char tmp_end[6] = {0}; + tm = localtime(&info_CurrentNext.next_zeit.startzeit); + snprintf(tmp_end, sizeof(tmp_end), "%02d:%02d", tm->tm_hour, tm->tm_min); + End = tmp_end; + } + } + } + + if(!g_settings.glcd_enable || doSuspend || doStandby) + { + // for restart, don't blacken screen + bitmap->Clear(GLCD::cColor::Black); + lcd->SetBrightness(0); + lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height()); + lcd->Refresh(false); + } + if(doExit) + { + if (g_settings.glcd_show_logo) + { + if (imageShow(DATADIR "/neutrino/icons/shutdown.jpg", 0, 0, 0, 0, false, true, true, false, false)) + { + lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height()); + lcd->Refresh(false); + sleep(3); + lcd->SetBrightness(0); + } + } else { + bitmap->Clear(GLCD::cColor::Black); + lcd->SetBrightness(0); + lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height()); + lcd->Refresh(false); + } + return; + } + if (doRescan) + { + doRescan = false; + Update(); + } + lcd->DeInit(); + delete lcd; + lcd = NULL; + } while(!doExit); +} + +void cGLCD::Update() +{ + if (cglcd) + { + sem_post(&cglcd->sem); + if (!cglcd->doExit) + cGLCD::getInstance()->WakeUp(); + } +} + +void cGLCD::StandbyMode(bool b) +{ + if (cglcd) + { + if (g_settings.glcd_time_in_standby) + { + cglcd->doStandbyTime = b; + cglcd->doStandby = false; + } else { + cglcd->doStandbyTime = false; + cglcd->doStandby = b; + } + if (b) + { + cglcd->doScrollChannel = false; + cglcd->doScrollEpg = false; + } else { + cglcd->doScrollChannel = true; + cglcd->doScrollEpg = true; + } + cglcd->doMirrorOSD = false; + cglcd->UpdateBrightness(); + cglcd->Update(); + } +} + +void cGLCD::ShowVolume(bool b) +{ + if (cglcd) + { + cglcd->doShowVolume = b; + cglcd->Update(); + } +} + +void cGLCD::ShowLcdIcon(bool b) +{ + if (cglcd) + { + cglcd->Lock(); + cglcd->doShowLcdIcon = b; + cglcd->Unlock(); + cglcd->Update(); + } +} + +void cGLCD::MirrorOSD(bool b) +{ + if (cglcd) + { + cglcd->doMirrorOSD = b; + cglcd->Update(); + } +} + +void cGLCD::Exit() +{ + if (cglcd) + { + cglcd->doMirrorOSD = false; + cglcd->doSuspend = false; + cglcd->time_thread_started = false; + cglcd->doExit = true; + cglcd->Update(); + void *res; + pthread_join(cglcd->thrGLCD, &res); + pthread_join(cglcd->thrTimeThread, NULL); + delete cglcd; + cglcd = NULL; + } +} + +void cGLCD::Rescan() +{ + doRescan = true; + Update(); +} + +void cGLCD::Suspend() +{ + if (cglcd) + { + cglcd->doSuspend = true; + cglcd->Update(); + } +} + +void cGLCD::Resume() +{ + if (cglcd) + { + cglcd->doSuspend = false; + cglcd->channelLocked = false; + cglcd->Update(); + } +} + +void cGLCD::lockChannel(std::string c, std::string e, int s) +{ + if(cglcd) + { + cglcd->Lock(); + cglcd->channelLocked = true; + cglcd->stagingChannel = c; + cglcd->stagingEpg = e; + cglcd->Scale = s; + cglcd->Unlock(); + cglcd->Update(); + } +} + +void cGLCD::unlockChannel(void) +{ + if(cglcd) + { + cglcd->channelLocked = false; + cglcd->Update(); + } +} + +void cGLCD::lockTime(std::string t) +{ + if(cglcd) + { + cglcd->Lock(); + cglcd->timeLocked = true; + cglcd->stagingTime = t; + cglcd->Unlock(); + cglcd->Update(); + } +} + +void cGLCD::unlockTime(void) +{ + if(cglcd) + { + cglcd->timeLocked = false; + cglcd->Update(); + } +} + +void cGLCD::lockDuration(std::string t) +{ + if(cglcd) + { + cglcd->Lock(); + cglcd->durationLocked = true; + cglcd->stagingDuration = t; + cglcd->Unlock(); + cglcd->Update(); + } +} + +void cGLCD::unlockDuration(void) +{ + if(cglcd) + { + cglcd->durationLocked = false; + cglcd->Update(); + } +} + +void cGLCD::lockStart(std::string t) +{ + if(cglcd) + { + cglcd->Lock(); + cglcd->startLocked = true; + cglcd->stagingStart = t; + cglcd->Unlock(); + cglcd->Update(); + } +} + +void cGLCD::unlockStart(void) +{ + if(cglcd) + { + cglcd->startLocked = false; + cglcd->Update(); + } +} + +void cGLCD::lockEnd(std::string t) +{ + if(cglcd) + { + cglcd->Lock(); + cglcd->endLocked = true; + cglcd->stagingEnd = t; + cglcd->Unlock(); + cglcd->Update(); + } +} + +void cGLCD::unlockEnd(void) +{ + if(cglcd) + { + cglcd->endLocked = false; + cglcd->Update(); + } +} + +void cGLCD::lockIcon(int type) +{ + if(cglcd) + { + cglcd->Lock(); + if (type == REC) + cglcd->recLocked = true; + else if (type == MUTE) + cglcd->muteLocked = true; + else if (type == TS) + cglcd->tsLocked = true; + else if (type == ECM) + cglcd->ecmLocked = true; + else if (type == TIMER) + cglcd->timerLocked = true; + else if (type == DD) + cglcd->ddLocked = true; + else if (type == TXT) + cglcd->txtLocked = true; + else if (type == SUB) + cglcd->subLocked = true; + else if (type == CAM) + cglcd->camLocked = true; + cglcd->Unlock(); + cglcd->Update(); + } +} + +void cGLCD::unlockIcon(int type) +{ + if(cglcd) + { + if (type == REC) + cglcd->recLocked = false; + else if (type == MUTE) + cglcd->muteLocked = false; + else if (type == TS) + cglcd->tsLocked = false; + else if (type == ECM) + cglcd->ecmLocked = false; + else if (type == TIMER) + cglcd->timerLocked = false; + else if (type == DD) + cglcd->ddLocked = false; + else if (type == TXT) + cglcd->txtLocked = false; + else if (type == SUB) + cglcd->subLocked = false; + else if (type == CAM) + cglcd->camLocked = false; + cglcd->Update(); + } +} + +bool cGLCD::showProgressBarBorder(uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2, uint32_t scale, uint32_t color_border, uint32_t color_progress) +{ + cglcd->bitmap->DrawRectangle(x1, y1, x1 + (x2 - x1 - 1), y2, color_border, false); + if (scale) { + cglcd->bitmap->DrawRectangle(x1 + 1, y1 + 1, x1 + (scale * (x2 - x1 - 1) / 100), y2 - 1, color_progress, true); + return true; + } else + return false; +} + +bool cGLCD::showImage(fb_pixel_t *s, uint32_t sw, uint32_t sh, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, bool transp, bool maximize) +{ + int bb_x, bb_y, bb_w, bb_h; + + if (cglcd->getBoundingBox(s, sw, sh, bb_x, bb_y, bb_w, bb_h) && bb_w && bb_h) + { + if (!maximize) + { + if (bb_h * dw > bb_w * dh) + { + uint32_t dw_new = dh * bb_w / bb_h; + dx += (dw - dw_new) >> 1; + dw = dw_new; + } else { + uint32_t dh_new = dw * bb_h / bb_w; + dy += (dh - dh_new) >> 1; + dh = dh_new; + } + } + for (u_int y = 0; y < dh; y++) + { + for (u_int x = 0; x < dw; x++) + { + uint32_t pix = *(s + (y * bb_h / dh + bb_y) * sw + x * bb_w / dw + bb_x); + if (!transp || pix) + cglcd->bitmap->DrawPixel(x + dx, y + dy, pix); + } + } + return true; + } + return false; +} + +bool cGLCD::showImage(const std::string & filename, uint32_t sw, uint32_t sh, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, bool transp, bool maximize) +{ + bool res = false; + if (!dw || !dh) + return res; + fb_pixel_t *s = g_PicViewer->getImage(filename, sw, sh); + if (s && sw && sh) + res = showImage(s, sw, sh, dx, dy, dw, dh, transp, maximize); + if (s) + free(s); + return res; +} + +bool cGLCD::showImage(uint64_t cid, std::string cname, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, bool transp, bool maximize) +{ + std::string logo; + int sw, sh; + + if (g_PicViewer->GetLogoName(cid, cname, logo, &sw, &sh)) + { + return showImage(logo, (uint32_t) sw, (uint32_t) sh, dx, dy, dw, dh, transp, maximize); + } + return false; +} + +bool cGLCD::imageShow(const std::string & filename, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, bool transp, bool maximize, bool clear, bool center_sw, bool center_sh) +{ + bool ret = false; + int sw, sh; + + g_PicViewer->getSize(filename.c_str(), &sw, &sh); + if (sw && sh) + { + if (clear) + cglcd->bitmap->Clear(GLCD::cColor::Black); + if (maximize) + ret = showImage(filename, (uint32_t) sw, (uint32_t) sh, (uint32_t) dx, (uint32_t) dy, (uint32_t) cglcd->bitmap->Width(), (uint32_t) cglcd->bitmap->Height(), transp, false); + else + if (center_sw || center_sh) + { + int move_sw = 0; + int move_sh = 0; + if (center_sw) + move_sw = dx - (sw / 2); + else + move_sw = dx; + if (center_sh) + move_sh = dy - (sh / 2); + else + move_sh = dy; + if (dw > 0 && dh > 0) + ret = showImage(filename, (uint32_t) sw, (uint32_t) sh, (uint32_t) move_sw, (uint32_t) move_sh, (uint32_t) dw, (uint32_t) dh, transp, false); + else + ret = showImage(filename, (uint32_t) sw, (uint32_t) sh, (uint32_t) move_sw, (uint32_t) move_sh, (uint32_t) sw, (uint32_t) sh, transp, false); + } + else + if (dw > 0 && dh > 0) + ret = showImage(filename, (uint32_t) sw, (uint32_t) sh, (uint32_t) dx, (uint32_t) dy, (uint32_t) dw, (uint32_t) dh, transp, false); + else + ret = showImage(filename, (uint32_t) sw, (uint32_t) sh, (uint32_t) dx, (uint32_t) dy, (uint32_t) sw, (uint32_t) sh, transp, false); + } + return ret; +} + +bool cGLCD::drawText(int x, int y, int xmax, int text_width, const std::string & text, const GLCD::cFont * font, uint32_t color1, uint32_t color2, bool proportional, int skipPixels, int align) +{ + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + + int z = 0; + + if (align == ALIGN_NONE) + { + z = x; + } + else if (align == ALIGN_LEFT) + { + z = std::max(2, (bitmap->Width() - 4 - text_width) / 24); + } + else if (align == ALIGN_CENTER) + { + z = std::max(2, (bitmap->Width() - 4 - text_width) / 2); + } + else if (align == ALIGN_RIGHT) + { + z = std::max(2, (bitmap->Width() - 4 - text_width)); + } + + return bitmap->DrawText(z, y, xmax, text, font, color1, color2, proportional, skipPixels); +} + +bool cGLCD::dumpBuffer(fb_pixel_t *s, int format, const char *filename) +{ + int output_bytes = 4; + + int jpg_quality = 90; + + int xres = bitmap->Width(); + int yres = bitmap->Height(); + + unsigned char *output = (unsigned char *)s; + + FILE *fd = fopen(filename, "wr"); + if (!fd) + return false; + + if(cglcd) + cglcd->Lock(); + + if (format == BMP) { + // write bmp + unsigned char hdr[14 + 40]; + int i = 0; +#define PUT32(x) hdr[i++] = ((x)&0xFF); hdr[i++] = (((x)>>8)&0xFF); hdr[i++] = (((x)>>16)&0xFF); hdr[i++] = (((x)>>24)&0xFF); +#define PUT16(x) hdr[i++] = ((x)&0xFF); hdr[i++] = (((x)>>8)&0xFF); +#define PUT8(x) hdr[i++] = ((x)&0xFF); + PUT8('B'); PUT8('M'); + PUT32((((xres * yres) * 3 + 3) &~ 3) + 14 + 40); + PUT16(0); PUT16(0); PUT32(14 + 40); + PUT32(40); PUT32(xres); PUT32(yres); + PUT16(1); + PUT16(output_bytes*8); // bits + PUT32(0); PUT32(0); PUT32(0); PUT32(0); PUT32(0); PUT32(0); +#undef PUT32 +#undef PUT16 +#undef PUT8 + fwrite(hdr, 1, i, fd); + + int y; + for (y=yres-1; y>=0 ; y-=1) + fwrite(output + (y * xres * output_bytes), xres * output_bytes, 1, fd); + } else if (format == JPG) { + const int row_stride = xres * output_bytes; + // write jpg + if (output_bytes == 3) // swap bgr<->rgb + { + int y; + #pragma omp parallel for shared(output) + for (y = 0; y < yres; y++) + { + int xres1 = y * xres * 3; + int xres2 = xres1 + 2; + int x; + for (x = 0; x < xres; x++) + { + int x2 = x * 3; + SWAP(output[x2 + xres1], output[x2 + xres2]); + } + } + } + else // swap bgr<->rgb and eliminate alpha channel jpgs are always saved with 24bit without alpha channel + { + int y; + #pragma omp parallel for shared(output) + for (y = 0; y < yres; y++) + { + unsigned char *scanline = output + (y * row_stride); + int x; + for (x=0; xUnlock(); + + fclose(fd); + return true; +} + +void cGLCD::UpdateBrightness() +{ + int dim_time = atoi(g_settings.glcd_brightness_dim_time.c_str()); + int dim_brightness = g_settings.glcd_brightness_dim; + bool timeouted = (dim_time > 0) && (timeout_cnt == 0); + + if (cglcd && cglcd->lcd) + { + if (timeouted && !cglcd->doStandbyTime) + cglcd->lcd->SetBrightness((unsigned int) (dim_brightness)); + else + cglcd->lcd->SetBrightness((unsigned int) (cglcd->doStandbyTime ? g_settings.glcd_brightness_standby : g_settings.glcd_brightness)); + + } +} + +void cGLCD::SetBrightness(unsigned int b) +{ + if (cglcd) + cglcd->SetBrightness(b); +} + +void cGLCD::TogglePower() +{ + if (cglcd) + { + cglcd->power_state = 1 - cglcd->power_state; + if (cglcd->power_state) + cglcd->Resume(); + else + cglcd->Suspend(); + } +} + +void cGLCD::Blit() +{ + if (cglcd) + cglcd->blitFlag = true; +} + +int cGLCD::handleMsg(const neutrino_msg_t msg, neutrino_msg_data_t /* data */) +{ + if (msg == NeutrinoMessages::EVT_CURRENTNEXT_EPG) + { + Update(); + return messages_return::handled; + } + + return messages_return::unhandled; +} + diff --git a/src/driver/nglcd.h b/src/driver/glcd.h similarity index 57% rename from src/driver/nglcd.h rename to src/driver/glcd.h index d9c40ace0..f80326a15 100644 --- a/src/driver/nglcd.h +++ b/src/driver/glcd.h @@ -33,6 +33,9 @@ #include #include +#define CLAMP(x) ((x < 0) ? 0 : ((x > 255) ? 255 : x)) +#define SWAP(x,y) { x ^= y; y ^= x; x ^= y; } + #pragma GCC diagnostic ignored "-Wunused-parameter" #include #include @@ -41,37 +44,53 @@ #include #pragma GCC diagnostic warning "-Wunused-parameter" -class nGLCD +class cGLCD { private: - GLCD::cDriver * lcd; - GLCD::cFont font_channel; - GLCD::cFont font_epg; - GLCD::cFont font_time; - GLCD::cFont font_time_standby; int fontsize_channel; int fontsize_epg; int fontsize_time; - int fontsize_time_standby; + int fontsize_duration; + int fontsize_start; + int fontsize_end; + int fontsize_smalltext; int percent_channel; int percent_time; - int percent_time_standby; + int percent_duration; + int percent_start; + int percent_end; int percent_epg; + int percent_smalltext; int percent_bar; int percent_logo; - int percent_space; int power_state; - GLCD::cBitmap * bitmap; + std::string Logo; std::string Channel; std::string Epg; + std::string Time; + std::string Duration; + std::string Start; + std::string End; + std::string Smalltext; + std::string Temperature; std::string stagingChannel; std::string stagingEpg; + std::string stagingTime; + std::string stagingDuration; + std::string stagingStart; + std::string stagingEnd; + std::string stagingSmalltext; t_channel_id channel_id; int Scale; time_t now; struct tm *tm; int EpgWidth; int ChannelWidth; + int TimeWidth; + int DurationWidth; + int StartWidth; + int EndWidth; + int SmalltextWidth; int scrollEpgSkip; int scrollChannelSkip; int scrollEpgOffset; @@ -80,6 +99,19 @@ class nGLCD bool scrollChannelForward; bool blitFlag; bool channelLocked; + bool timeLocked; + bool durationLocked; + bool startLocked; + bool endLocked; + bool recLocked; + bool muteLocked; + bool tsLocked; + bool ecmLocked; + bool timerLocked; + bool ddLocked; + bool txtLocked; + bool subLocked; + bool camLocked; bool doRescan; bool doSuspend; bool doStandby; @@ -88,9 +120,15 @@ class nGLCD bool doScrollChannel; bool doScrollEpg; bool doShowVolume; + bool doShowLcdIcon; bool doMirrorOSD; bool fonts_initialized; + bool ismediaplayer; + int timeout_cnt; + bool locked_countdown; + bool time_thread_started; pthread_t thrGLCD; + pthread_t thrTimeThread; pthread_mutex_t mutex; sem_t sem; void updateFonts(); @@ -108,40 +146,79 @@ class nGLCD bool getBoundingBox(uint32_t *buffer, int width, int height, int &bb_x, int &bb_y, int &bb_width, int &bb_height); - void LcdAnalogClock(int posx,int posy,int dia); void Exec(); + void CountDown(); + void WakeUp(); + static void *TimeThread(void *); void Run(void); static void* Run(void *); static void Lock(); static void Unlock(); public: - enum - { - CLOCK_OFF = 0, - CLOCK_DIGITAL_HM = 1, - CLOCK_DIGITAL_HMS = 2, - CLOCK_ANALOG = 3 + enum { + BMP = 0, + JPG = 1, + PNG = 2, }; - - nGLCD(); - ~nGLCD(); + enum { + ALIGN_NONE = 0, + ALIGN_LEFT = 1, + ALIGN_CENTER = 2, + ALIGN_RIGHT = 3, + }; + enum { + REC = 0, + MUTE = 1, + TS = 2, + ECM = 3, + TIMER = 4, + DD = 5, + TXT = 6, + SUB = 7, + CAM = 8, + }; + GLCD::cDriver * lcd; + GLCD::cFont font_channel; + GLCD::cFont font_epg; + GLCD::cFont font_time; + GLCD::cFont font_duration; + GLCD::cFont font_start; + GLCD::cFont font_end; + GLCD::cFont font_smalltext; + GLCD::cBitmap * bitmap; + cGLCD(); + ~cGLCD(); + uint32_t ColorConvert3to1(uint32_t red, uint32_t green, uint32_t blue); void DeInit(); void Rescan(); - static nGLCD *getInstance(); + bool showProgressBarBorder(uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2, uint32_t scale, uint32_t color_border, uint32_t color_progress); + bool imageShow(const std::string & filename, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, bool transp = false, bool maximize = false, bool clear = false, bool center_sw = false, bool center_sh = false); + bool drawText(int x, int y, int xmax, int text_width, const std::string & text, const GLCD::cFont * font, uint32_t color1, uint32_t color2, bool proportional, int skipPixels, int align); + static cGLCD *getInstance(); static void lockChannel(std::string txt, std::string epg = "", int scale = 0); static void unlockChannel(); + static void lockTime(std::string time); + static void unlockTime(); + static void lockDuration(std::string time); + static void unlockDuration(); + static void lockStart(std::string time); + static void unlockStart(); + static void lockEnd(std::string time); + static void unlockEnd(); + static void lockIcon(int type = 0); + static void unlockIcon(int type = 0); static void MirrorOSD(bool b = true); static void Update(); static void Suspend(); static void StandbyMode(bool); static void ShowVolume(bool); + static void ShowLcdIcon(bool); static void Resume(); static void Exit(); static void Blit(); static void SetBrightness(unsigned int b); static void TogglePower(); - int GetConfigSize(); - std::string GetConfigName(int); + bool dumpBuffer(fb_pixel_t *s, int format, const char *filename); void UpdateBrightness(); int handleMsg(const neutrino_msg_t msg, neutrino_msg_data_t data); }; diff --git a/src/driver/lcdclock.cpp b/src/driver/lcdclock.cpp new file mode 100644 index 000000000..d75380680 --- /dev/null +++ b/src/driver/lcdclock.cpp @@ -0,0 +1,74 @@ +/* + simple clock - DBoxII-Project + + Copyright (C) 2018 redblue + + License: GPL + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include + +static bool fonts_initialized = false; + +GLCD::cFont font_time_standby_second; + +void InitLcdClock(void) +{ + printf("[%s:%s] finish initialization\n", __file__, __func__); +} + +void LcdClockUpdateFonts(void) +{ + cGLCD *cglcd = cGLCD::getInstance(); + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + int fontsize_time_standby = 0; + int percent_time_standby = std::min(t.glcd_size_simple_clock, 100); + int fontsize_time_standby_new = percent_time_standby * cglcd->lcd->Height() / 100; + if (!fonts_initialized || (fontsize_time_standby_new != fontsize_time_standby)) { + fontsize_time_standby = fontsize_time_standby_new; + if (!font_time_standby_second.LoadFT2(/*t.glcd_font*/FONTDIR "/lcd.ttf", "UTF-8", fontsize_time_standby)) { + t.glcd_font = FONTDIR "/lcd.ttf"; + font_time_standby_second.LoadFT2(t.glcd_font, "UTF-8", fontsize_time_standby); + } + } + fonts_initialized = true; +} + +void RenderLcdClock(std::string Time, int x, int y) +{ + cGLCD *cglcd = cGLCD::getInstance(); + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + LcdClockUpdateFonts(); + cglcd->bitmap->DrawText(std::max(2,(cglcd->bitmap->Width() - 4 - font_time_standby_second.Width(Time))/2), + y, cglcd->bitmap->Width() - 1, Time, + &font_time_standby_second, cglcd->ColorConvert3to1(t.glcd_color_fg_red, t.glcd_color_fg_green, t.glcd_color_fg_blue), GLCD::cColor::Transparent); +} + +void ShowLcdClock(std::string Time) +{ + cGLCD *cglcd = cGLCD::getInstance(); + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + int y = g_settings.glcd_standby_weather ? t.glcd_simple_clock_y_position : (cglcd->bitmap->Height() - font_time_standby_second.Height(Time)) / 2; + RenderLcdClock(Time, 255, y); +} diff --git a/src/driver/lcdclock.h b/src/driver/lcdclock.h new file mode 100644 index 000000000..0965690ec --- /dev/null +++ b/src/driver/lcdclock.h @@ -0,0 +1,34 @@ +/* + LCD-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + + + License: GPL + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#pragma GCC diagnostic ignored "-Wunused-parameter" +#include +#pragma GCC diagnostic warning "-Wunused-parameter" +#include "glcd.h" + +void InitLcdClock(); +void LcdClockUpdateFonts(); +void RenderLcdClock(std::string Time, int x, int y); +void ShowLcdClock(std::string Time); diff --git a/src/driver/ledclock.cpp b/src/driver/ledclock.cpp new file mode 100644 index 000000000..908194929 --- /dev/null +++ b/src/driver/ledclock.cpp @@ -0,0 +1,74 @@ +/* + simple clock - DBoxII-Project + + Copyright (C) 2018 redblue + + License: GPL + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include + +static bool fonts_initialized = false; + +GLCD::cFont second_font_time_standby; + +void InitLedClock(void) +{ + printf("[%s:%s] finish initialization\n", __file__, __func__); +} + +void LedClockUpdateFonts(void) +{ + cGLCD *cglcd = cGLCD::getInstance(); + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + int fontsize_time_standby = 0; + int percent_time_standby = std::min(t.glcd_size_simple_clock, 100); + int fontsize_time_standby_new = percent_time_standby * cglcd->lcd->Height() / 100; + if (!fonts_initialized || (fontsize_time_standby_new != fontsize_time_standby)) { + fontsize_time_standby = fontsize_time_standby_new; + if (!second_font_time_standby.LoadFT2(/*t.glcd_font*/FONTDIR "/led.ttf", "UTF-8", fontsize_time_standby)) { + t.glcd_font = FONTDIR "/led.ttf"; + second_font_time_standby.LoadFT2(t.glcd_font, "UTF-8", fontsize_time_standby); + } + } + fonts_initialized = true; +} + +void RenderLedClock(std::string Time, int x, int y) +{ + cGLCD *cglcd = cGLCD::getInstance(); + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + LedClockUpdateFonts(); + cglcd->bitmap->DrawText(std::max(2,(cglcd->bitmap->Width() - 4 - second_font_time_standby.Width(Time))/2), + y, cglcd->bitmap->Width() - 1, Time, + &second_font_time_standby, cglcd->ColorConvert3to1(t.glcd_color_fg_red, t.glcd_color_fg_green, t.glcd_color_fg_blue), GLCD::cColor::Transparent); +} + +void ShowLedClock(std::string Time) +{ + cGLCD *cglcd = cGLCD::getInstance(); + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + int y = g_settings.glcd_standby_weather ? t.glcd_simple_clock_y_position : (cglcd->bitmap->Height() - second_font_time_standby.Height(Time)) / 2; + RenderLedClock(Time, 255, y); +} diff --git a/src/driver/ledclock.h b/src/driver/ledclock.h new file mode 100644 index 000000000..8479fac8d --- /dev/null +++ b/src/driver/ledclock.h @@ -0,0 +1,34 @@ +/* + LCD-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + + + License: GPL + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#pragma GCC diagnostic ignored "-Wunused-parameter" +#include +#pragma GCC diagnostic warning "-Wunused-parameter" +#include "glcd.h" + +void InitLedClock(); +void LedClockUpdateFonts(); +void RenderLedClock(std::string Time, int x, int y); +void ShowLedClock(std::string Time); diff --git a/src/driver/nglcd.cpp b/src/driver/nglcd.cpp deleted file mode 100644 index 207241083..000000000 --- a/src/driver/nglcd.cpp +++ /dev/null @@ -1,983 +0,0 @@ -/* - Neutrino graphlcd daemon thread - - (C) 2012-2014 by martii - - - License: GPL - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define LCD_ICONSDIR "/share/lcd/icons/" - -static const char * kDefaultConfigFile = "/etc/graphlcd.conf"; -static nGLCD *nglcd = NULL; - -extern CPictureViewer * g_PicViewer; - -nGLCD::nGLCD() { - lcd = NULL; - Channel = "Neutrino"; - Epg = std::string(g_info.hw_caps->boxvendor) + " " + std::string(g_info.hw_caps->boxname); - - sem_init(&sem, 0, 1); - - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP); - pthread_mutex_init(&mutex, &attr); - - channelLocked = false; - doRescan = false; - doStandby = false; - doStandbyTime = false; - doShowVolume = false; - doSuspend = false; - doExit = false; - doMirrorOSD = false; - fontsize_channel = 0; - fontsize_epg = 0; - fontsize_time = 0; - fontsize_time_standby = 0; - fonts_initialized = false; - doScrollChannel = false; - doScrollEpg = false; - percent_channel = 0; - percent_time = 0; - percent_time_standby = 0; - percent_epg = 0; - percent_bar = 0; - percent_space = 0; - percent_logo = 0; - power_state = 1; - Scale = 0; - bitmap = NULL; - blitFlag = true; - - nglcd = this; - - if (!g_settings.glcd_enable) - doSuspend = true; - - if (pthread_create (&thrGLCD, 0, nGLCD::Run, this) != 0 ) - fprintf(stderr, "ERROR: pthread_create(nGLCD::Init)\n"); - - Update(); -} - -void nGLCD::Lock(void) -{ - if (nglcd) - pthread_mutex_lock(&nglcd->mutex); -} - -void nGLCD::Unlock(void) -{ - if (nglcd) - pthread_mutex_unlock(&nglcd->mutex); -} - -nGLCD::~nGLCD() { - Suspend(); - nglcd = NULL; - if (lcd) { - lcd->DeInit(); - delete lcd; - } - sem_destroy(&sem); - pthread_mutex_destroy(&mutex); -} - -nGLCD *nGLCD::getInstance() -{ - if (!nglcd) - nglcd = new nGLCD; - return nglcd; -} - -void nGLCD::LcdAnalogClock(int posx,int posy,int dia) -{ - int tm_,th_,mx_,my_,hx_,hy_; - double pi_ = 3.1415926535897932384626433832795, mAngleInRad, mAngleSave, hAngleInRad; - - tm_ = tm->tm_min; - th_ = tm->tm_hour; - - mAngleInRad = ((6 * tm_) * (2*pi_ / 360)); - mAngleSave = mAngleInRad; - mAngleInRad -= pi_/2; -#if BOXMODEL_VUUNO4KSE - mx_ = int((dia * 0.55 * cos(mAngleInRad))); - my_ = int((dia * 0.55 * sin(mAngleInRad))); -#else - mx_ = int((dia * 0.7 * cos(mAngleInRad))); - my_ = int((dia * 0.7 * sin(mAngleInRad))); -#endif - - hAngleInRad = ((30 * th_)* (2*pi_ / 360)); - hAngleInRad += mAngleSave / 12; - hAngleInRad -= pi_/2; -#if BOXMODEL_VUUNO4KSE - hx_ = int((dia * 0.25 * cos(hAngleInRad))); - hy_ = int((dia * 0.25 * sin(hAngleInRad))); -#else - hx_ = int((dia * 0.4 * cos(hAngleInRad))); - hy_ = int((dia * 0.4 * sin(hAngleInRad))); -#endif - - std::string clock_face = LCD_ICONSDIR "/clock/analog/dial.png"; - - int clock_face_width = 0, clock_face_height = 0; - g_PicViewer->getSize(clock_face.c_str(), &clock_face_width, &clock_face_height); - if (clock_face_width && clock_face_height) - { - showImage(clock_face, (uint32_t) clock_face_width, (uint32_t) clock_face_height, - 0, 0, (uint32_t) nglcd->bitmap->Width(), (uint32_t) nglcd->bitmap->Height(), false, false); - - lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height()); - lcd->Refresh(true); - } - - // TODO: Fix these ugly and buggy clock hands - - // hour - bitmap->DrawLine(posx,posy-8,posx+hx_,posy+hy_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy-7,posx+hx_,posy+hy_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy-6,posx+hx_,posy+hy_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy-5,posx+hx_,posy+hy_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy-4,posx+hx_,posy+hy_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy-3,posx+hx_,posy+hy_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy-2,posx+hx_,posy+hy_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy-1,posx+hx_,posy+hy_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx+1,posy,posx+hx_,posy+hy_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy+1,posx+hx_,posy+hy_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy+2,posx+hx_,posy+hy_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy+3,posx+hx_,posy+hy_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy+4,posx+hx_,posy+hy_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy+5,posx+hx_,posy+hy_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy+6,posx+hx_,posy+hy_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy+7,posx+hx_,posy+hy_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy+8,posx+hx_,posy+hy_, g_settings.glcd_color_fg); - - // minute - bitmap->DrawLine(posx,posy-6,posx+mx_,posy+my_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy-5,posx+mx_,posy+my_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy-4,posx+mx_,posy+my_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy-3,posx+mx_,posy+my_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy-2,posx+mx_,posy+my_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy-1,posx+mx_,posy+my_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx+1,posy,posx+mx_,posy+my_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy+1,posx+mx_,posy+my_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy+2,posx+mx_,posy+my_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy+3,posx+mx_,posy+my_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy+4,posx+mx_,posy+my_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy+5,posx+mx_,posy+my_, g_settings.glcd_color_fg); - bitmap->DrawLine(posx,posy+6,posx+mx_,posy+my_, g_settings.glcd_color_fg); -} - -void nGLCD::Exec() { - if (!lcd) - return; - - bitmap->Clear(g_settings.glcd_color_bg); - - if (Channel.compare("Neutrino") == 0) { - int start_width = 0, start_height = 0; - g_PicViewer->getSize(DATADIR "/neutrino/icons/start.jpg", &start_width, &start_height); - if (start_width && start_height) { - showImage(DATADIR "/neutrino/icons/start.jpg", (uint32_t) start_width, (uint32_t) start_height, - 0, 0, (uint32_t) nglcd->bitmap->Width(), (uint32_t) nglcd->bitmap->Height(), false, true); - - GLCD::cFont font_tmp; - int fw = font_epg.Width(Epg); - font_tmp.LoadFT2(g_settings.glcd_font, "UTF-8", fontsize_epg * (bitmap->Width() - 4) / fw); - fw = font_tmp.Width(Epg); - - bitmap->DrawText(std::max(2,(bitmap->Width() - 4 - fw)/2), - 10 * bitmap->Height()/100, bitmap->Width() - 4, Epg, - &font_tmp, g_settings.glcd_color_fg, GLCD::cColor::Transparent); - - lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height()); - lcd->Refresh(true); - } - return; - } - - if (doStandbyTime) { - if (percent_time_standby) { - - std::string Time; - if (g_settings.glcd_time_in_standby == CLOCK_ANALOG) - LcdAnalogClock(bitmap->Width()/2, bitmap->Height()/2, 200); - else if (g_settings.glcd_time_in_standby == CLOCK_DIGITAL_HMS) - Time = strftime("%H:%M:%S", tm); - else - Time = strftime("%H:%M", tm); - - bitmap->DrawText(std::max(2,(bitmap->Width() - 4 - font_time_standby.Width(Time))/2), - (bitmap->Height() - font_time_standby.Height(Time))/2, bitmap->Width() - 1, Time, - &font_time_standby, g_settings.glcd_color_fg, GLCD::cColor::Transparent); - lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height()); - lcd->Refresh(false); - } - return; - } - - if (CNeutrinoApp::getInstance()->recordingstatus) { -#if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUULTIMO4K || BOXMODEL_VUUNO4KSE || BOXMODEL_VUUNO4K - for (int bx = 0; bx < 9; bx++) { -#else - for (int bx = 0; bx < 3; bx++) { -#endif - bitmap->DrawRectangle(bx, bx, bitmap->Width() - bx + 1, bitmap->Height() - bx + 1, GLCD::cColor::Red, false); - } - } else - if (CNeutrinoApp::getInstance()->isMuted()) { -#if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUULTIMO4K || BOXMODEL_VUUNO4KSE || BOXMODEL_VUUNO4K - for (int bx = 0; bx < 9; bx++) { -#else - for (int bx = 0; bx < 3; bx++) { -#endif - bitmap->DrawRectangle(bx, bx, bitmap->Width() - bx + 1, bitmap->Height() - bx + 1, GLCD::cColor::Blue, false); - } - } - - int off = percent_space; - - if (g_settings.glcd_show_logo && percent_logo && - showImage(channel_id, Channel, 0, off * bitmap->Height()/100, bitmap->Width() - 4, percent_logo * bitmap->Height()/100, true)) { - off += percent_logo; - off += percent_space; - doScrollChannel = false; - scrollChannelSkip = 0; - } else if (percent_channel) { - int logo_offset = 0; - if (g_settings.glcd_show_logo && percent_channel < percent_logo) { - int o = logo_offset = percent_logo - percent_channel; - o >>= 1; - off += o; - logo_offset -= o; - } - if (ChannelWidth) { - if (scrollChannelForward) { - if (ChannelWidth - scrollChannelSkip < bitmap->Width() - 4) - scrollChannelForward = false; - } else if (scrollChannelSkip <= 0) { - scrollChannelSkip = 0; - doScrollChannel = false; - } - - bitmap->DrawText(std::max(2,(bitmap->Width() - 4 - ChannelWidth)/2) + scrollChannelOffset, - off * bitmap->Height()/100, bitmap->Width() - 4, Channel, - &font_channel, g_settings.glcd_color_fg, GLCD::cColor::Transparent, true, scrollChannelSkip); - - if (scrollChannelOffset > 0) - scrollChannelOffset -= g_settings.glcd_scroll_speed; - - if (scrollChannelOffset < 0) - scrollChannelOffset = 0; - - if (scrollChannelOffset == 0) { - if (scrollChannelForward) - scrollChannelSkip += g_settings.glcd_scroll_speed; - else - scrollChannelSkip -= g_settings.glcd_scroll_speed; - } - } - off += percent_channel; - off += logo_offset; - off += percent_space; - } else - off = 0; - - if (percent_epg) { - off += percent_space; - if (EpgWidth) { - if (scrollEpgForward) { - if (EpgWidth - scrollEpgSkip < bitmap->Width() - 4) - scrollEpgForward = false; - } else if (scrollEpgSkip <= 0) { - scrollEpgSkip = 0; - doScrollEpg = false; - } - - bitmap->DrawText(std::max(2,(bitmap->Width() - 4 - EpgWidth)/2) + scrollEpgOffset, - off * bitmap->Height()/100, bitmap->Width() - 4, Epg, - &font_epg, g_settings.glcd_color_fg, GLCD::cColor::Transparent, true, scrollEpgSkip); - - if (scrollEpgOffset > 0) - scrollEpgOffset -= g_settings.glcd_scroll_speed; - - if (scrollEpgOffset < 0) - scrollEpgOffset = 0; - - if (scrollEpgOffset == 0) { - if (scrollEpgForward) - scrollEpgSkip += g_settings.glcd_scroll_speed; - else - scrollEpgSkip -= g_settings.glcd_scroll_speed; - } - } - off += percent_epg; - off += percent_space; - } - - if (percent_bar) { - off += percent_space; - int bar_top = off * bitmap->Height()/100; - off += percent_bar; - int bar_bottom = off * bitmap->Height()/100; - bitmap->DrawHLine(0, bar_top, bitmap->Width(), g_settings.glcd_color_fg); - bitmap->DrawHLine(0, bar_bottom, bitmap->Width(), g_settings.glcd_color_fg); - if (Scale) - bitmap->DrawRectangle(0, bar_top + 1, Scale * (bitmap->Width() - 1)/100, - bar_bottom - 1, g_settings.glcd_color_bar, true); - off += percent_space; - } - - if (percent_time) { - off += percent_space; - std::string Time = strftime("%H:%M", tm); - bitmap->DrawText(std::max(2,(bitmap->Width() - 4 - font_time.Width(Time))/2), - off * bitmap->Height()/100, bitmap->Width() - 1, Time, - &font_time, g_settings.glcd_color_fg, GLCD::cColor::Transparent); - } - - lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height()); - lcd->Refresh(false); -} - -void nGLCD::updateFonts() { - int percent; - percent = std::max(g_settings.glcd_percent_channel, g_settings.glcd_show_logo ? g_settings.glcd_percent_logo : 0) - + g_settings.glcd_percent_epg + g_settings.glcd_percent_bar + g_settings.glcd_percent_time; - - int div = 0; - - if (percent_channel || percent_logo) - div += 2; - if (percent_epg) - div += 2; - if (percent_bar) - div += 2; - if (percent_time) - div += 2; - - percent += div; - - if (percent < 100) - percent = 100; - - percent_logo = g_settings.glcd_show_logo ? g_settings.glcd_percent_logo * 100 / percent : 0; - percent_channel = g_settings.glcd_percent_channel * 100 / percent; - percent_epg = g_settings.glcd_percent_epg * 100 / percent; - percent_bar = g_settings.glcd_percent_bar * 100 / percent; - percent_time = g_settings.glcd_percent_time * 100 / percent; - percent_time_standby = std::min(g_settings.glcd_percent_time_standby, 100); - - percent_space = (100 - std::max(percent_logo, percent_channel) - percent_time - percent_epg - percent_bar) / div; - - // calculate height - int fontsize_channel_new = percent_channel * nglcd->lcd->Height() / 100; - int fontsize_epg_new = percent_epg * nglcd->lcd->Height() / 100; - int fontsize_time_new = percent_time * nglcd->lcd->Height() / 100; - int fontsize_time_standby_new = percent_time_standby * nglcd->lcd->Height() / 100; - - if (!fonts_initialized || (fontsize_channel_new != fontsize_channel)) { - fontsize_channel = fontsize_channel_new; - if (!font_channel.LoadFT2(g_settings.glcd_font, "UTF-8", fontsize_channel)) { - g_settings.glcd_font = FONTDIR "/neutrino.ttf"; - font_channel.LoadFT2(g_settings.glcd_font, "UTF-8", fontsize_channel); - } - } - if (!fonts_initialized || (fontsize_epg_new != fontsize_epg)) { - fontsize_epg = fontsize_epg_new; - if (!font_epg.LoadFT2(g_settings.glcd_font, "UTF-8", fontsize_epg)) { - g_settings.glcd_font = FONTDIR "/neutrino.ttf"; - font_epg.LoadFT2(g_settings.glcd_font, "UTF-8", fontsize_epg); - } - } - if (!fonts_initialized || (fontsize_time_new != fontsize_time)) { - fontsize_time = fontsize_time_new; - if (!font_time.LoadFT2(g_settings.glcd_font, "UTF-8", fontsize_time)) { - g_settings.glcd_font = FONTDIR "/neutrino.ttf"; - font_time.LoadFT2(g_settings.glcd_font, "UTF-8", fontsize_time); - } - } - if (!fonts_initialized || (fontsize_time_standby_new != fontsize_time_standby)) { - fontsize_time_standby = fontsize_time_standby_new; - if (!font_time_standby.LoadFT2(g_settings.glcd_font, "UTF-8", fontsize_time_standby)) { - g_settings.glcd_font = FONTDIR "/neutrino.ttf"; - font_time_standby.LoadFT2(g_settings.glcd_font, "UTF-8", fontsize_time_standby); - } - } - - fonts_initialized = true; -} - -bool nGLCD::getBoundingBox(uint32_t *buffer, int width, int height, int &bb_x, int &bb_y, int &bb_w, int &bb_h) -{ - if (!width || !height) { - bb_x = bb_y = bb_w = bb_h = 0; - return false; - } - - int y_min = height; - uint32_t *b = buffer; - for (int y = 0; y < height; y++) - for (int x = 0; x < width; x++, b++) - if (*b) { - y_min = y; - goto out1; - } - out1: - - int y_max = y_min; - b = buffer + height * width - 1; - for (int y = height - 1; y_min < y; y--) - for (int x = 0; x < width; x++, b--) - if (*b) { - y_max = y; - goto out2; - } - out2: - - int x_min = width; - for (int x = 0; x < width; x++) { - b = buffer + x + y_min * width; - for (int y = y_min; y < y_max; y++, b += width) - if (*b) { - x_min = x; - goto out3; - } - } - out3: - - int x_max = x_min; - for (int x = width - 1; x_min < x; x--) { - b = buffer + x + y_min * width; - for (int y = y_min; y < y_max; y++, b += width) - if (*b) { - x_max = x; - goto out4; - } - } - out4: - - bb_x = x_min; - bb_y = y_min; - bb_w = 1 + x_max - x_min; - bb_h = 1 + y_max - y_min; - - if (bb_x < 0) - bb_x = 0; - if (bb_y < 0) - bb_y = 0; - - return true; -} - -void* nGLCD::Run(void *arg) -{ - nGLCD *me = (nGLCD *) arg; - me->Run(); - pthread_exit(NULL); -} - -void nGLCD::Run(void) -{ - set_threadname("nGLCD::Run"); - - if (GLCD::Config.Load(kDefaultConfigFile) == false) { - fprintf(stderr, "Error loading config file!\n"); - return; - } - if ((GLCD::Config.driverConfigs.size() < 1)) { - fprintf(stderr, "No driver config found!\n"); - return; - } - - struct timespec ts; - - CSectionsdClient::CurrentNextInfo info_CurrentNext; - channel_id = -1; - info_CurrentNext.current_zeit.startzeit = 0; - info_CurrentNext.current_zeit.dauer = 0; - info_CurrentNext.flags = 0; - - fonts_initialized = false; - bool broken = false; - - do { - if (broken) { -#ifdef GLCD_DEBUG - fprintf(stderr, "No graphlcd display found ... sleeping for 30 seconds\n"); -#endif - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += 30; - sem_timedwait(&sem, &ts); - broken = false; - if (doExit) - break; - if (!g_settings.glcd_enable) - continue; - } else - while ((doSuspend || doStandby || !g_settings.glcd_enable) && !doExit) - sem_wait(&sem); - - if (doExit) - break; - - int warmUp = 10; - - if ((g_settings.glcd_selected_config < 0) || (g_settings.glcd_selected_config > GetConfigSize() - 1)) - g_settings.glcd_selected_config = 0; - - lcd = GLCD::CreateDriver(GLCD::Config.driverConfigs[g_settings.glcd_selected_config].id, &GLCD::Config.driverConfigs[g_settings.glcd_selected_config]); - if (!lcd) { -#ifdef GLCD_DEBUG - fprintf(stderr, "CreateDriver failed.\n"); -#endif - broken = true; - continue; - } -#ifdef GLCD_DEBUG - fprintf(stderr, "CreateDriver succeeded.\n"); -#endif - if (lcd->Init()) { - delete lcd; - lcd = NULL; -#ifdef GLCD_DEBUG - fprintf(stderr, "LCD init failed.\n"); -#endif - broken = true; - continue; - } -#ifdef GLCD_DEBUG - fprintf(stderr, "LCD init succeeded.\n"); -#endif - lcd->SetBrightness(0); - - if (!bitmap) - bitmap = new GLCD::cBitmap(lcd->Width(), lcd->Height(), g_settings.glcd_color_bg); - - UpdateBrightness(); - Update(); - - doMirrorOSD = false; - - while ((!doSuspend && !doStandby) && !doExit && g_settings.glcd_enable) { - if (doMirrorOSD && !doStandbyTime) { - if (blitFlag) { - blitFlag = false; - bitmap->Clear(GLCD::cColor::Black); - ts.tv_sec = 0; // don't wait - static CFrameBuffer* fb = CFrameBuffer::getInstance(); -#if !BOXMODEL_VUSOLO4K && !BOXMODEL_VUDUO4K && !BOXMODEL_VUULTIMO4K && !BOXMODEL_VUUNO4KSE - static int fb_width = fb->getScreenWidth(true); -#endif - static int fb_height = fb->getScreenHeight(true); - static uint32_t *fbp = fb->getFrameBufferPointer(); - int lcd_width = bitmap->Width(); - int lcd_height = bitmap->Height(); -#if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUULTIMO4K || BOXMODEL_VUUNO4KSE - unsigned int fb_stride = fb->getStride()/4; - if (!showImage(fbp, fb_stride, fb_height, 0, 0, lcd_width, lcd_height, false)) { -#else - if (!showImage(fbp, fb_width, fb_height, 0, 0, lcd_width, lcd_height, false)) { -#endif - usleep(500000); - } else { - lcd->SetScreen(bitmap->Data(), lcd_width, lcd_height); - lcd->Refresh(false); - } - } else - usleep(100000); - continue; - } - if (g_settings.glcd_mirror_video && !doStandbyTime) { - char ws[10]; - snprintf(ws, sizeof(ws), "%d", bitmap->Width()); - const char *bmpShot = "/tmp/nglcd-video.bmp"; - my_system(4, "/bin/grab", "-vr", ws, bmpShot); - int bw = 0, bh = 0; - g_PicViewer->getSize(bmpShot, &bw, &bh); - if (bw > 0 && bh > 0) { - int lcd_width = bitmap->Width(); - int lcd_height = bitmap->Height(); - if (!showImage(bmpShot, (uint32_t) bw, (uint32_t) bh, 0, 0, (uint32_t) lcd_width, lcd_height, false, true)) - usleep(1000000); - else { - lcd->SetScreen(bitmap->Data(), lcd_width, lcd_height); - lcd->Refresh(false); - } - } - else - usleep(1000000); - continue; - } - - clock_gettime(CLOCK_REALTIME, &ts); - tm = localtime(&ts.tv_sec); - updateFonts(); - Exec(); - clock_gettime(CLOCK_REALTIME, &ts); - tm = localtime(&ts.tv_sec); - if (warmUp > 0) { - ts.tv_sec += 1; - warmUp--; - } else { - ts.tv_sec += 60 - tm->tm_sec; - ts.tv_nsec = 0; - } - - if (!doScrollChannel && !doScrollEpg) - sem_timedwait(&sem, &ts); - - while(!sem_trywait(&sem)); - - if(doRescan || doSuspend || doStandby || doExit) - break; - - if (doShowVolume) { - Epg = ""; - if (Channel.compare(g_Locale->getText(LOCALE_GLCD_VOLUME))) { - Channel = g_Locale->getText(LOCALE_GLCD_VOLUME); - ChannelWidth = font_channel.Width(Channel); - doScrollChannel = ChannelWidth > bitmap->Width() - 4; - scrollChannelSkip = 0; - scrollChannelForward = true; - if (doScrollChannel) { - scrollChannelOffset = bitmap->Width()/g_settings.glcd_scroll_speed; - ChannelWidth += scrollChannelOffset; - } else - scrollChannelOffset = 0; - } - EpgWidth = 0; - scrollEpgSkip = 0; - scrollEpgForward = true; - Scale = g_settings.current_volume; - channel_id = -1; - } else if (channelLocked) { - Lock(); - if (Epg.compare(stagingEpg)) { - Epg = stagingEpg; - EpgWidth = font_epg.Width(Epg); - doScrollEpg = EpgWidth > bitmap->Width() - 4; - scrollEpgSkip = 0; - scrollEpgForward = true; - if (doScrollEpg) { - scrollEpgOffset = bitmap->Width()/g_settings.glcd_scroll_speed; - EpgWidth += scrollEpgOffset; - } else - scrollChannelOffset = 0; - } - if (Channel.compare(stagingChannel)) { - Channel = stagingChannel; - ChannelWidth = font_channel.Width(Channel); - doScrollChannel = ChannelWidth > bitmap->Width() - 4; - scrollChannelSkip = 0; - scrollChannelForward = true; - if (doScrollChannel) { - scrollChannelOffset = bitmap->Width()/g_settings.glcd_scroll_speed; - ChannelWidth += scrollChannelOffset; - } else - scrollChannelOffset = 0; - } - channel_id = -1; - Unlock(); - } else { - CChannelList *channelList = CNeutrinoApp::getInstance ()->channelList; - if (!channelList) - continue; - t_channel_id new_channel_id = channelList->getActiveChannel_ChannelID(); - if (!new_channel_id) - continue; - - if ((new_channel_id != channel_id)) { - Channel = channelList->getActiveChannelName (); - ChannelWidth = font_channel.Width(Channel); - Epg = ""; - EpgWidth = 0; - Scale = 0; - doScrollEpg = false; - doScrollChannel = ChannelWidth > bitmap->Width() - 4; - scrollChannelForward = true; - scrollChannelSkip = 0; - if (doScrollChannel) { - scrollChannelOffset = bitmap->Width()/g_settings.glcd_scroll_speed; - ChannelWidth += scrollChannelOffset; - } else - scrollChannelOffset = 0; - warmUp = 10; - info_CurrentNext.current_name = ""; - info_CurrentNext.current_zeit.dauer = 0; - } - - CEitManager::getInstance()->getCurrentNextServiceKey(channel_id & 0xFFFFFFFFFFFFULL, info_CurrentNext); - channel_id = new_channel_id; - - if (info_CurrentNext.current_name.compare(Epg)) { - Epg = info_CurrentNext.current_name; - EpgWidth = font_epg.Width(Epg); - doScrollEpg = EpgWidth > bitmap->Width() - 4; - scrollEpgForward = true; - scrollEpgSkip = 0; - if (doScrollEpg) { - scrollEpgOffset = bitmap->Width()/g_settings.glcd_scroll_speed; - EpgWidth += scrollEpgOffset; - } else - scrollEpgOffset = 0; - } - if (info_CurrentNext.current_zeit.dauer > 0) - Scale = (ts.tv_sec - info_CurrentNext.current_zeit.startzeit) * 100 / info_CurrentNext.current_zeit.dauer; - if (Scale > 100) - Scale = 100; - else if (Scale < 0) - Scale = 0; - } - } - - if(!g_settings.glcd_enable || doSuspend || doStandby || doExit) { - // for restart, don't blacken screen - bitmap->Clear(GLCD::cColor::Black); - lcd->SetBrightness(0); - lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height()); - lcd->Refresh(false); - } - if (doRescan) { - doRescan = false; - Update(); - } - lcd->DeInit(); - delete lcd; - lcd = NULL; - } while(!doExit); -} - -void nGLCD::Update() { - if (nglcd) - sem_post(&nglcd->sem); -} - -void nGLCD::StandbyMode(bool b) { - if (nglcd) { - if (g_settings.glcd_time_in_standby != CLOCK_OFF) { - nglcd->doStandbyTime = b; - nglcd->doStandby = false; - } else { - nglcd->doStandbyTime = false; - nglcd->doStandby = b; - } - if (b) { - nglcd->doScrollChannel = false; - nglcd->doScrollEpg = false; - } else { - nglcd->doScrollChannel = true; - nglcd->doScrollEpg = true; - } - nglcd->doMirrorOSD = false; - nglcd->UpdateBrightness(); - nglcd->Update(); - } -} - -void nGLCD::ShowVolume(bool b) { - if (nglcd) { - nglcd->doShowVolume = b; - nglcd->Update(); - } -} - -void nGLCD::MirrorOSD(bool b) { - if (nglcd) { - nglcd->doMirrorOSD = b; - nglcd->Update(); - } -} - -void nGLCD::Exit() { - if (nglcd) { - nglcd->doMirrorOSD = false; - nglcd->doSuspend = false; - nglcd->doExit = true; - nglcd->Update(); - void *res; - pthread_join(nglcd->thrGLCD, &res); - delete nglcd; - nglcd = NULL; - } -} - -void nGLCD::Rescan() { - doRescan = true; - Update(); -} - -void nGLCD::Suspend() { - if (nglcd) { - nglcd->doSuspend = true; - nglcd->Update(); - } -} - -void nGLCD::Resume() { - if (nglcd) { - nglcd->doSuspend = false; - nglcd->channelLocked = false; - nglcd->Update(); - } -} - -void nGLCD::lockChannel(std::string c, std::string e, int s) -{ - if(nglcd) { - nglcd->Lock(); - nglcd->channelLocked = true; - nglcd->stagingChannel = c; - nglcd->stagingEpg = e; - nglcd->Scale = s; - nglcd->Unlock(); - nglcd->Update(); - } -} - -void nGLCD::unlockChannel(void) -{ - if(nglcd) { - nglcd->channelLocked = false; - nglcd->Update(); - } -} - -bool nGLCD::showImage(fb_pixel_t *s, uint32_t sw, uint32_t sh, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, bool transp, bool maximize) -{ - int bb_x, bb_y, bb_w, bb_h; - - if (nglcd->getBoundingBox(s, sw, sh, bb_x, bb_y, bb_w, bb_h) && bb_w && bb_h) { - if (!maximize) { - if (bb_h * dw > bb_w * dh) { - uint32_t dw_new = dh * bb_w / bb_h; - dx += (dw - dw_new) >> 1; - dw = dw_new; - } else { - uint32_t dh_new = dw * bb_h / bb_w; - dy += (dh - dh_new) >> 1; - dh = dh_new; - } - } - for (u_int y = 0; y < dh; y++) { - for (u_int x = 0; x < dw; x++) { - uint32_t pix = *(s + (y * bb_h / dh + bb_y) * sw + x * bb_w / dw + bb_x); - if (!transp || pix) - nglcd->bitmap->DrawPixel(x + dx, y + dy, pix); - } - } - return true; - } - return false; -} - -bool nGLCD::showImage(const std::string & filename, uint32_t sw, uint32_t sh, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, bool transp, bool maximize) -{ - bool res = false; - if (!dw || !dh) - return res; - fb_pixel_t *s = g_PicViewer->getImage(filename, sw, sh); - if (s && sw && sh) - res = showImage(s, sw, sh, dx, dy, dw, dh, transp, maximize); - if (s) - free(s); - return res; -} - -bool nGLCD::showImage(uint64_t cid, std::string cname, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, bool transp, bool maximize) -{ - std::string logo; - int sw, sh; - - if (g_PicViewer->GetLogoName(cid, cname, logo, &sw, &sh)) { - return showImage(logo, (uint32_t) sw, (uint32_t) sh, dx, dy, dw, dh, transp, maximize); - } - return false; -} - -void nGLCD::UpdateBrightness() -{ - if (nglcd && nglcd->lcd) - nglcd->lcd->SetBrightness((unsigned int) (nglcd->doStandbyTime ? g_settings.glcd_brightness_standby : g_settings.glcd_brightness)); -} - -void nGLCD::SetBrightness(unsigned int b) -{ - if (nglcd) - nglcd->SetBrightness(b); -} - -void nGLCD::TogglePower() -{ - if (nglcd) - { - nglcd->power_state = 1 - nglcd->power_state; - if (nglcd->power_state) - nglcd->Resume(); - else - nglcd->Suspend(); - } -} - -void nGLCD::Blit() -{ - if (nglcd) - nglcd->blitFlag = true; -} - -int nGLCD::handleMsg(const neutrino_msg_t msg, neutrino_msg_data_t /* data */) -{ - if (msg == NeutrinoMessages::EVT_CURRENTNEXT_EPG) { - Update(); - return messages_return::handled; - } - - return messages_return::unhandled; -} - -int nGLCD::GetConfigSize() -{ - return (int) GLCD::Config.driverConfigs.size(); -} - -std::string nGLCD::GetConfigName(int driver) -{ - if ((driver < 0) || (driver > GetConfigSize() - 1)) - driver = 0; - return GLCD::Config.driverConfigs[driver].name; -} diff --git a/src/driver/record.cpp b/src/driver/record.cpp index 82706d33e..3ea9dee02 100644 --- a/src/driver/record.cpp +++ b/src/driver/record.cpp @@ -310,6 +310,16 @@ record_error_msg_t CRecordInstance::Start(CZapitChannel * channel) CCamManager::getInstance()->Start(channel->getChannelID(), CCamManager::RECORD); //CVFD::getInstance()->ShowIcon(VFD_ICON_CAM1, true); +#ifdef ENABLE_GRAPHLCD + if (CRecordManager::getInstance()->GetRecordMode() == CRecordManager::RECMODE_REC) + cGLCD::lockIcon(cGLCD::REC); + else if (CRecordManager::getInstance()->GetRecordMode() == CRecordManager::RECMODE_TSHIFT) + cGLCD::lockIcon(cGLCD::TS); + else if (CRecordManager::getInstance()->GetRecordMode() == CRecordManager::RECMODE_REC_TSHIFT) { + cGLCD::lockIcon(cGLCD::REC); + cGLCD::lockIcon(cGLCD::TS); + } +#endif WaitRecMsg(msg_start_time, 2); hintBox.hide(); return RECORD_OK; @@ -356,6 +366,9 @@ bool CRecordInstance::Stop(bool remove_event) recording_id = 0; } //CVFD::getInstance()->ShowIcon(VFD_ICON_CAM1, false); +#ifdef ENABLE_GRAPHLCD + cGLCD::unlockIcon(cGLCD::REC); +#endif WaitRecMsg(end_time, 2); hintBox.hide(); return true; @@ -1119,7 +1132,7 @@ bool CRecordManager::Record(const CTimerd::RecordingInfo * const eventinfo, cons recordingstatus = 1; #endif #ifdef ENABLE_GRAPHLCD - nGLCD::Update(); + cGLCD::Update(); #endif } else { delete inst; @@ -1326,7 +1339,7 @@ bool CRecordManager::Stop(const CTimerd::RecordingStopInfo * recinfo) StopInstance(inst, false); ret = true; #ifdef ENABLE_GRAPHLCD - nGLCD::Update(); + cGLCD::Update(); #endif } else { for(nextmap_iterator_t it = nextmap.begin(); it != nextmap.end(); it++) { diff --git a/src/driver/simpleclock.cpp b/src/driver/simpleclock.cpp new file mode 100644 index 000000000..d5685cde9 --- /dev/null +++ b/src/driver/simpleclock.cpp @@ -0,0 +1,74 @@ +/* + simple clock - DBoxII-Project + + Copyright (C) 2018 redblue + + License: GPL + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include + +static bool fonts_initialized = false; + +GLCD::cFont font_time_standby; + +void InitSimpleClock(void) +{ + printf("[%s:%s] finish initialization\n", __file__, __func__); +} + +void SimpleClockUpdateFonts(void) +{ + cGLCD *cglcd = cGLCD::getInstance(); + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + int fontsize_time_standby = 0; + int percent_time_standby = std::min(t.glcd_size_simple_clock, 100); + int fontsize_time_standby_new = percent_time_standby * cglcd->lcd->Height() / 100; + if (!fonts_initialized || (fontsize_time_standby_new != fontsize_time_standby)) { + fontsize_time_standby = fontsize_time_standby_new; + if (!font_time_standby.LoadFT2(t.glcd_font, "UTF-8", fontsize_time_standby)) { + t.glcd_font = FONTDIR "/neutrino.ttf"; + font_time_standby.LoadFT2(t.glcd_font, "UTF-8", fontsize_time_standby); + } + } + fonts_initialized = true; +} + +void RenderSimpleClock(std::string Time, int x, int y) +{ + cGLCD *cglcd = cGLCD::getInstance(); + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + SimpleClockUpdateFonts(); + cglcd->bitmap->DrawText(std::max(2,(cglcd->bitmap->Width() - 4 - font_time_standby.Width(Time))/2), + y, cglcd->bitmap->Width() - 1, Time, + &font_time_standby, cglcd->ColorConvert3to1(t.glcd_color_fg_red, t.glcd_color_fg_green, t.glcd_color_fg_blue), GLCD::cColor::Transparent); +} + +void ShowSimpleClock(std::string Time) +{ + cGLCD *cglcd = cGLCD::getInstance(); + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + int y = g_settings.glcd_standby_weather ? t.glcd_simple_clock_y_position : (cglcd->bitmap->Height() - font_time_standby.Height(Time)) / 2; + RenderSimpleClock(Time, 255, y); +} diff --git a/src/driver/simpleclock.h b/src/driver/simpleclock.h new file mode 100644 index 000000000..0767d5cf0 --- /dev/null +++ b/src/driver/simpleclock.h @@ -0,0 +1,34 @@ +/* + LCD-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + + + License: GPL + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#pragma GCC diagnostic ignored "-Wunused-parameter" +#include +#pragma GCC diagnostic warning "-Wunused-parameter" +#include "glcd.h" + +void InitSimpleClock(); +void SimpleClockUpdateFonts(); +void RenderSimpleClock(std::string Time, int x, int y); +void ShowSimpleClock(std::string Time); diff --git a/src/driver/volume.cpp b/src/driver/volume.cpp index 225ae2282..e6c1def00 100644 --- a/src/driver/volume.cpp +++ b/src/driver/volume.cpp @@ -174,7 +174,7 @@ void CVolume::setVolume(const neutrino_msg_t key) } g_settings.current_volume = v; #ifdef ENABLE_GRAPHLCD - nGLCD::ShowVolume(true); + cGLCD::ShowVolume(true); #endif } } @@ -211,7 +211,7 @@ void CVolume::setVolume(const neutrino_msg_t key) } while (msg != CRCInput::RC_timeout); #ifdef ENABLE_GRAPHLCD - nGLCD::ShowVolume(false); + cGLCD::ShowVolume(false); #endif hideVolscale(); } diff --git a/src/driver/weather.cpp b/src/driver/weather.cpp new file mode 100644 index 000000000..47555f6e5 --- /dev/null +++ b/src/driver/weather.cpp @@ -0,0 +1,270 @@ +/* + weather - DBoxII-Project + + Copyright (C) 2018 redblue + + License: GPL + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#include +#include +#include +#include +#include + +enum weathers +{ + CLEAR_DAY = 0, + CLEAR_NIGHT = 1, + CLOUDY = 2, + FOG = 3, + PARTLY_CLOUDY_DAY = 4, + PARTLY_CLOUDY_NIGHT = 5, + RAIN = 6, + SLEET = 7, + SNOW = 8, + WIND = 9, + //WEATHER_UNKNOWN = 10 +}; + +const char * const weather_name[LCD_NUMBER_OF_WEATHERS] = +{ + "clear-day", + "clear-night", + "cloudy", + "fog", + "partly-cloudy-day", + "partly-cloudy-night", + "rain", + "sleet", + "snow", + "wind", + //"unknown" +}; + +#define NUMBER_OF_PATHS 2 +const char * const weather_path[NUMBER_OF_PATHS] = +{ + LCDDIR_VAR "/oled/weather/", + DATADIR "/oled/weather/" +}; + +static bool ForceUpdate = true; +static bool fonts_initialized = false; + +GLCD::cFont font_temperature; + +static std::string weather[LCD_NUMBER_OF_WEATHERS] = {""}; + +static std::string st_current_wcity = ""; +static std::string st_current_wtimestamp = ""; +static std::string st_current_wtemp = ""; +static std::string st_current_wwind = ""; +static std::string st_current_wicon = ""; + +static std::string st_next_wcity = ""; +static std::string st_next_wtimestamp = ""; +static std::string st_next_wtemp = ""; +static std::string st_next_wwind = ""; +static std::string st_next_wicon = ""; + +void InitWeather(void) +{ + for (int i = 0; i < LCD_NUMBER_OF_WEATHERS; i++) + { + std::string weather_file; + for (int j = 0; j < NUMBER_OF_PATHS; j++) + { + std::string file_jpg = weather_path[j]; + file_jpg += weather_name[i]; + file_jpg += ".jpg"; + if (file_exists(file_jpg.c_str())) + { + weather_file = file_jpg; + goto found; + } + std::string file_jpeg = weather_path[j]; + file_jpeg += weather_name[i]; + file_jpeg += ".jpeg"; + if (file_exists(file_jpeg.c_str())) + { + weather_file = file_jpeg; + goto found; + } + std::string file_png = weather_path[j]; + file_png += weather_name[i]; + file_png += ".png"; + if (file_exists(file_png.c_str())) + { + weather_file = file_png; + goto found; + } + std::string file_bmp = weather_path[j]; + file_bmp += weather_name[i]; + file_bmp += ".bmp"; + if (file_exists(file_bmp.c_str())) + { + weather_file = file_bmp; + goto found; + } + std::string file_gif = weather_path[j]; + file_gif += weather_name[i]; + file_gif += ".gif"; + if (file_exists(file_gif.c_str())) + { + weather_file = file_gif; + goto found; + } + } +found: + printf("[%s:%s] found file: %s\n", __file__, __func__, weather_file.c_str()); + weather[i] += std::string(weather_file); + } + printf("[%s:%s] finish initialization\n", __file__, __func__); +} + +void WeatherUpdateFonts(void) +{ + cGLCD *cglcd = cGLCD::getInstance(); + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + int fontsize_temperature = 0; + int percent_temperature = std::min(24, 100); + int fontsize_temperature_new = percent_temperature * cglcd->lcd->Height() / 100; + if (!fonts_initialized || (fontsize_temperature_new != fontsize_temperature)) { + fontsize_temperature = fontsize_temperature_new; + if (!font_temperature.LoadFT2(/*t.glcd_font*/FONTDIR "/pakenham.ttf", "UTF-8", fontsize_temperature)) { + t.glcd_font = FONTDIR "/pakenham.ttf"; + font_temperature.LoadFT2(t.glcd_font, "UTF-8", fontsize_temperature); + } + } + fonts_initialized = true; +} + +int WeatherNameToNumber(std::string name) +{ + std::map weather_name + { + { "clear-day", 0 }, + { "clear-night", 1 }, + { "cloudy", 2 }, + { "fog", 3 }, + { "partly-cloudy-day", 4 }, + { "partly-cloudy-night", 5 }, + { "rain", 6 }, + { "sleet", 7 }, + { "snow", 8 }, + { "wind", 9 }, + //{ "unknown", 10 }, + }; + + const auto iter = weather_name.find(name); + + if (iter != weather_name.cend()) + return iter->second; +} + +void RenderWeather(int cx, int cy, int nx, int ny, bool standby) +{ + int forecast = 0; + + std::string current_wcity = ""; + std::string current_wtimestamp = ""; + std::string current_wtemp = ""; + std::string current_wwind = ""; + std::string current_wicon = ""; + + std::string next_wcity = ""; + std::string next_wtimestamp = ""; + std::string next_wtemp = ""; + std::string next_wwind = ""; + std::string next_wicon = ""; + + cGLCD *cglcd = cGLCD::getInstance(); + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + if (g_settings.weather_enabled) + { + if (CWeather::getInstance()->checkUpdate(ForceUpdate)) + { + current_wcity = st_current_wcity = CWeather::getInstance()->getCity(); + current_wtimestamp = st_current_wtimestamp = to_string((int)CWeather::getInstance()->getCurrentTimestamp()); + current_wtemp = st_current_wtemp = CWeather::getInstance()->getCurrentTemperature(); + current_wwind = st_current_wwind = CWeather::getInstance()->getCurrentWindSpeed(); + current_wicon = st_current_wicon = CWeather::getInstance()->getCurrentIconOnlyName(); + + next_wcity = st_next_wcity = CWeather::getInstance()->getCity(); + next_wtimestamp = st_next_wtimestamp = to_string((int)CWeather::getInstance()->getForecastWeekday(forecast)); + next_wtemp = st_next_wtemp = CWeather::getInstance()->getForecastTemperatureMin(forecast); + next_wtemp = st_next_wtemp += "|" + CWeather::getInstance()->getForecastTemperatureMax(forecast); + next_wwind = st_next_wwind = CWeather::getInstance()->getForecastWindBearing(forecast); + next_wicon = st_next_wicon = CWeather::getInstance()->getForecastIconOnlyNane(forecast); + } + else + { + current_wcity = st_current_wcity; + current_wtimestamp = st_current_wtimestamp; + current_wtemp = st_current_wtemp; + current_wwind = st_current_wwind; + current_wicon = st_current_wicon; + + next_wcity = st_next_wcity; + next_wtimestamp = st_next_wtimestamp; + next_wtemp = st_next_wtemp; + next_wwind = st_next_wwind; + next_wicon = st_next_wicon; + } + + if (current_wicon != "") { + if (!standby) + cglcd->imageShow(weather[WeatherNameToNumber(current_wicon)], cx, cy, 64, 64, false, false, false, false, false); + else + cglcd->imageShow(weather[WeatherNameToNumber(current_wicon)], cx, cy, 0, 0, false, false, false, false, false); + } + if (current_wtemp != "") { + current_wtemp += "°"; + WeatherUpdateFonts(); + cglcd->bitmap->DrawText(170, 240, cglcd->bitmap->Width() - 1, current_wtemp, + &font_temperature, cglcd->ColorConvert3to1(t.glcd_color_fg_red, t.glcd_color_fg_green, t.glcd_color_fg_blue), GLCD::cColor::Transparent); + } + if (next_wicon != "") { + if (!standby) + cglcd->imageShow(weather[WeatherNameToNumber(next_wicon)], nx, ny, 64, 64, false, false, false, false, false); + else + cglcd->imageShow(weather[WeatherNameToNumber(next_wicon)], nx, ny, 0, 0, false, false, false, false, false); + } + if (next_wtemp != "") { + next_wtemp += "°"; + WeatherUpdateFonts(); + cglcd->bitmap->DrawText(270, 240, cglcd->bitmap->Width() - 1, next_wtemp, + &font_temperature, cglcd->ColorConvert3to1(t.glcd_color_fg_red, t.glcd_color_fg_green, t.glcd_color_fg_blue), GLCD::cColor::Transparent); + } + } +} + +void ShowWeather(bool standby) +{ + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + + if (!standby) { + RenderWeather(t.glcd_weather_x_position_current, t.glcd_weather_y_position, t.glcd_weather_x_position_next, t.glcd_weather_y_position, standby); + } else { + RenderWeather(t.glcd_weather_x_position_current_standby, t.glcd_weather_y_position_standby, t.glcd_weather_x_position_next_standby, t.glcd_weather_y_position_standby, standby); + } + + if (ForceUpdate) + ForceUpdate = false; +} diff --git a/src/driver/weather.h b/src/driver/weather.h new file mode 100644 index 000000000..c1860f487 --- /dev/null +++ b/src/driver/weather.h @@ -0,0 +1,39 @@ +/* + LCD-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + + + License: GPL + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#pragma GCC diagnostic ignored "-Wunused-parameter" +#include +#pragma GCC diagnostic warning "-Wunused-parameter" +#include "glcd.h" + +#define LCDDIR_VAR "/usr/share/tuxbox/neutrino/icons" + +#define LCD_NUMBER_OF_WEATHERS 10 + +void InitWeather(); +void WeatherUpdateFonts(); +int WeatherNameToNumber(std::string name); +void RenderWeather(int cx, int cy, int nx, int ny, bool standby); +void ShowWeather(bool standby); diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index ba754b3e2..8a71befb2 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -121,7 +121,8 @@ libneutrino_gui_a_SOURCES = \ if ENABLE_GRAPHLCD libneutrino_gui_a_SOURCES += \ - glcdsetup.cpp + glcdsetup.cpp \ + glcdthemes.cpp endif if BOXTYPE_COOL diff --git a/src/gui/audiomute.cpp b/src/gui/audiomute.cpp index 928410450..803da7024 100644 --- a/src/gui/audiomute.cpp +++ b/src/gui/audiomute.cpp @@ -63,6 +63,12 @@ void CAudioMute::AudioMute(int newValue, bool isEvent) bool doInit = newValue != (int) neutrino->isMuted(); CVFD::getInstance()->setMuted(newValue); +#ifdef ENABLE_GRAPHLCD + if (newValue) + cGLCD::lockIcon(cGLCD::MUTE); + else + cGLCD::unlockIcon(cGLCD::MUTE); +#endif neutrino->setCurrentMuted(newValue); #if HAVE_ARM_HARDWARE || HAVE_MIPS_HARDWARE if (g_settings.hdmi_cec_volume) diff --git a/src/gui/audioplayer.cpp b/src/gui/audioplayer.cpp index 0212e730c..048c858cb 100644 --- a/src/gui/audioplayer.cpp +++ b/src/gui/audioplayer.cpp @@ -313,6 +313,10 @@ int CAudioPlayerGui::exec(CMenuTarget* parent, const std::string &actionKey) printf("[audioplayer.cpp] wakeup_hdd(%s)\n", g_settings.network_nfs_audioplayerdir.c_str()); wakeup_hdd(g_settings.network_nfs_audioplayerdir.c_str(),true); +#ifdef ENABLE_GRAPHLCD + cGLCD::MirrorOSD(false); +#endif + exec_controlscript(AUDIOPLAYER_START_SCRIPT); int res = show(); @@ -334,6 +338,15 @@ int CAudioPlayerGui::exec(CMenuTarget* parent, const std::string &actionKey) CNeutrinoApp::getInstance()->StartSubtitles(); +#ifdef ENABLE_GRAPHLCD + cGLCD::MirrorOSD(g_settings.glcd_mirror_osd); + cGLCD::unlockChannel(); + cGLCD::unlockDuration(); + cGLCD::unlockStart(); + cGLCD::unlockEnd(); + cGLCD::ShowLcdIcon(false); +#endif + return res; } @@ -2372,6 +2385,27 @@ void CAudioPlayerGui::updateTimes(const bool force) } if ((updatePlayed || updateTotal) && m_curr_audiofile.FileType != CFile::STREAM_AUDIO && m_time_total != 0) { +#ifdef ENABLE_GRAPHLCD + //glcd_duration = to_string(m_time_played / (60 * 1000)) + "/" + to_string(m_time_total / (60 * 1000)); + glcd_duration = to_string(m_time_played/60) + ":" + to_string(m_time_played%60) + "/" + to_string(m_time_total/60) + ":" + to_string(m_time_total%60); + + time_t sTime = time(NULL); + sTime -= m_time_played; + tm_struct = localtime(&sTime); + start = to_string(tm_struct->tm_hour/10) + to_string(tm_struct->tm_hour%10) + ":" + to_string(tm_struct->tm_min/10) + to_string(tm_struct->tm_min%10); + + time_t eTime = time(NULL); + eTime += m_time_total - m_time_played; + tm_struct = localtime(&eTime); + end = to_string(tm_struct->tm_hour/10) + to_string(tm_struct->tm_hour%10) + ":" + to_string(tm_struct->tm_min/10) + to_string(tm_struct->tm_min%10); + + glcd_position = 100 * m_time_played / m_time_total; + + cGLCD::lockChannel(channel, epg, uint8_t(glcd_position)); + cGLCD::lockDuration(glcd_duration); + cGLCD::lockStart(start); + cGLCD::lockEnd(end); +#endif CVFD::getInstance()->showAudioProgress(uint8_t(100 * m_time_played / m_time_total)); } } @@ -2379,27 +2413,82 @@ void CAudioPlayerGui::updateTimes(const bool force) void CAudioPlayerGui::paintLCD() { +#ifdef ENABLE_GRAPHLCD + const CAudioMetaData meta = CAudioPlayer::getInstance()->getMetaData(); + if ( !meta.artist.empty() ) + epg = meta.artist; + if ( !meta.artist.empty() && !meta.title.empty() ) + epg = " - "; + if ( !meta.title.empty() ) + epg = meta.title; +#endif switch (m_state) { case CAudioPlayerGui::STOP: +#ifdef ENABLE_GRAPHLCD + if (m_inetmode) + channel = g_Locale->getText(LOCALE_INETRADIO_NAME); + else + channel = g_Locale->getText(LOCALE_AUDIOPLAYER_NAME); + + epg = g_Locale->getText(LOCALE_MPKEY_STOP); + + cGLCD::ShowLcdIcon(false); + cGLCD::lockChannel(channel, epg, 0); + cGLCD::lockDuration("00/00"); + cGLCD::lockStart("00:00"); + cGLCD::lockEnd("00:00"); +#endif CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_STOP); CVFD::getInstance()->showAudioProgress(0); break; case CAudioPlayerGui::PLAY: +#ifdef ENABLE_GRAPHLCD + channel = ""; + cGLCD::lockChannel(channel, epg, uint8_t(glcd_position)); + cGLCD::lockDuration(glcd_duration); + cGLCD::lockStart(start); + cGLCD::lockEnd(end); + cGLCD::ShowLcdIcon(true); +#endif CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_PLAY); CVFD::getInstance()->showAudioTrack(m_curr_audiofile.MetaData.artist, m_curr_audiofile.MetaData.title, m_curr_audiofile.MetaData.album); if (m_curr_audiofile.FileType != CFile::STREAM_AUDIO && m_time_total != 0) CVFD::getInstance()->showAudioProgress(uint8_t(100 * m_time_played / m_time_total)); break; case CAudioPlayerGui::PAUSE: +#ifdef ENABLE_GRAPHLCD + channel = ""; + cGLCD::lockChannel(channel, epg, uint8_t(glcd_position)); + cGLCD::lockDuration(glcd_duration); + cGLCD::lockStart(start); + cGLCD::lockEnd(end); + cGLCD::ShowLcdIcon(true); +#endif CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_PAUSE); CVFD::getInstance()->showAudioTrack(m_curr_audiofile.MetaData.artist, m_curr_audiofile.MetaData.title, m_curr_audiofile.MetaData.album); break; case CAudioPlayerGui::FF: +#ifdef ENABLE_GRAPHLCD + channel = ""; + cGLCD::lockChannel(channel, epg, uint8_t(glcd_position)); + cGLCD::lockDuration(glcd_duration); + cGLCD::lockStart(start); + cGLCD::lockEnd(end); + cGLCD::ShowLcdIcon(true); +#endif CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_FF); CVFD::getInstance()->showAudioTrack(m_curr_audiofile.MetaData.artist, m_curr_audiofile.MetaData.title, m_curr_audiofile.MetaData.album); break; case CAudioPlayerGui::REV: +#ifdef ENABLE_GRAPHLCD + channel = ""; + cGLCD::lockChannel(channel, epg, uint8_t(glcd_position)); + cGLCD::lockDuration(glcd_duration); + cGLCD::lockStart(start); + cGLCD::lockEnd(end); + cGLCD::ShowLcdIcon(true); +#endif CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_REV); CVFD::getInstance()->showAudioTrack(m_curr_audiofile.MetaData.artist, m_curr_audiofile.MetaData.title, m_curr_audiofile.MetaData.album); break; diff --git a/src/gui/audioplayer.h b/src/gui/audioplayer.h index d83ab6f0d..e1a02dcd3 100644 --- a/src/gui/audioplayer.h +++ b/src/gui/audioplayer.h @@ -114,6 +114,16 @@ class CAudioPlayerGui : public CMenuTarget bool m_streamripper_available; bool m_streamripper_active; +#if ENABLE_GRAPHLCD + struct tm *tm_struct; + int glcd_position; + std::string channel; + std::string epg; + std::string glcd_duration; + std::string start; + std::string end; +#endif + CAudioPlayList m_playlist; CAudioPlayList m_radiolist; CAudioPlayList m_filelist; diff --git a/src/gui/bouquetlist.cpp b/src/gui/bouquetlist.cpp index 2e3d3c3db..8028c8c00 100644 --- a/src/gui/bouquetlist.cpp +++ b/src/gui/bouquetlist.cpp @@ -593,7 +593,7 @@ int CBouquetList::show(bool bShowChannelList) hide(); #ifdef ENABLE_GRAPHLCD - nGLCD::unlockChannel(); + cGLCD::unlockChannel(); #endif LCD4l->RemoveFile("/tmp/lcd/menu"); @@ -656,7 +656,7 @@ void CBouquetList::paintItem(int pos) CVFD::getInstance()->showMenuText(0, lname, -1, true); #ifdef ENABLE_GRAPHLCD if(g_settings.glcd_enable) - nGLCD::lockChannel(g_Locale->getText(LOCALE_BOUQUETLIST_HEAD), lname, 0); + cGLCD::lockChannel(g_Locale->getText(LOCALE_BOUQUETLIST_HEAD), lname, 0); #endif if(g_settings.lcd4l_support) LCD4l->CreateFile("/tmp/lcd/menu", lname, g_settings.lcd4l_convert); diff --git a/src/gui/cec_setup.cpp b/src/gui/cec_setup.cpp index 3a154ad88..048f55ca5 100644 --- a/src/gui/cec_setup.cpp +++ b/src/gui/cec_setup.cpp @@ -47,7 +47,15 @@ #include #include +#if HAVE_SH4_HARDWARE +#include +#include +#include +#include +#include +#else extern cVideo *videoDecoder; +#endif CCECSetup::CCECSetup() { @@ -76,21 +84,38 @@ int CCECSetup::exec(CMenuTarget* parent, const std::string &/*actionKey*/) } +#if HAVE_SH4_HARDWARE +#define VIDEOMENU_HDMI_CEC_STANDBY_OPTION_COUNT 3 +const CMenuOptionChooser::keyval VIDEOMENU_HDMI_CEC_STANDBY_OPTIONS[VIDEOMENU_HDMI_CEC_STANDBY_OPTION_COUNT] = +{ + { 0 , LOCALE_OPTIONS_OFF }, + { 1 , LOCALE_OPTIONS_ON }, + { 2 , LOCALE_VIDEOMENU_HDMI_CEC_STANDBY_NOT_TIMER } +}; +#else #define VIDEOMENU_HDMI_CEC_MODE_OPTION_COUNT 3 const CMenuOptionChooser::keyval VIDEOMENU_HDMI_CEC_MODE_OPTIONS[VIDEOMENU_HDMI_CEC_MODE_OPTION_COUNT] = { { VIDEO_HDMI_CEC_MODE_OFF , LOCALE_VIDEOMENU_HDMI_CEC_MODE_OFF }, { VIDEO_HDMI_CEC_MODE_TUNER , LOCALE_VIDEOMENU_HDMI_CEC_MODE_TUNER }, - { VIDEO_HDMI_CEC_MODE_RECORDER , LOCALE_VIDEOMENU_HDMI_CEC_MODE_RECORDER }, + { VIDEO_HDMI_CEC_MODE_RECORDER , LOCALE_VIDEOMENU_HDMI_CEC_MODE_RECORDER } }; +#endif int CCECSetup::showMenu() { //menue init - CMenuWidget *cec = new CMenuWidget(LOCALE_MISCSETTINGS_HEAD, NEUTRINO_ICON_SETTINGS, width, MN_WIDGET_ID_CEC); + CMenuWidget *cec = new CMenuWidget(LOCALE_MAINMENU_SETTINGS, NEUTRINO_ICON_SETTINGS, width, MN_WIDGET_ID_CEC); cec->addIntroItems(LOCALE_VIDEOMENU_HDMI_CEC); //cec +#if HAVE_SH4_HARDWARE + CKernelOptions ko; + g_settings.hdmi_cec_mode = ko.isEnabled("cec"); + CMenuOptionChooser *cec_ch = new CMenuOptionChooser(LOCALE_VIDEOMENU_HDMI_CEC_MODE, &g_settings.hdmi_cec_mode, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, this); + cec1 = new CMenuOptionChooser(LOCALE_VIDEOMENU_HDMI_CEC_STANDBY, &g_settings.hdmi_cec_standby, VIDEOMENU_HDMI_CEC_STANDBY_OPTIONS, VIDEOMENU_HDMI_CEC_STANDBY_OPTION_COUNT, g_settings.hdmi_cec_mode != 0, this); + cec2 = new CMenuOptionChooser(LOCALE_VIDEOMENU_HDMI_CEC_BROADCAST, &g_settings.hdmi_cec_broadcast, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, g_settings.hdmi_cec_mode != VIDEO_HDMI_CEC_MODE_OFF, this); +#else CMenuOptionChooser *cec_ch = new CMenuOptionChooser(LOCALE_VIDEOMENU_HDMI_CEC_MODE, &g_settings.hdmi_cec_mode, VIDEOMENU_HDMI_CEC_MODE_OPTIONS, VIDEOMENU_HDMI_CEC_MODE_OPTION_COUNT, true, this); cec_ch->setHint("", LOCALE_MENU_HINT_CEC_MODE); cec1 = new CMenuOptionChooser(LOCALE_VIDEOMENU_HDMI_CEC_VIEW_ON, &g_settings.hdmi_cec_view_on, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, g_settings.hdmi_cec_mode != VIDEO_HDMI_CEC_MODE_OFF, this); @@ -100,10 +125,13 @@ int CCECSetup::showMenu() #if HAVE_ARM_HARDWARE || HAVE_MIPS_HARDWARE cec3 = new CMenuOptionChooser(LOCALE_VIDEOMENU_HDMI_CEC_VOLUME, &g_settings.hdmi_cec_volume, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, g_settings.hdmi_cec_mode != VIDEO_HDMI_CEC_MODE_OFF, this); cec3->setHint("", LOCALE_MENU_HINT_CEC_VOLUME); +#endif #endif cec->addItem(cec_ch); +#if !HAVE_SH4_HARDWARE cec->addItem(GenericMenuSeparatorLine); +#endif //------------------------------------------------------- cec->addItem(cec1); cec->addItem(cec2); @@ -117,6 +145,32 @@ int CCECSetup::showMenu() return res; } +#if HAVE_SH4_HARDWARE +void CCECSetup::setCECSettings(bool b) +{ + printf("[neutrino CEC Settings] %s init CEC settings...\n", __FUNCTION__); + if (b) { + // wakeup + if (g_settings.hdmi_cec_mode && + ((g_settings.hdmi_cec_standby == 1) || + (g_settings.hdmi_cec_standby == 2 && !CNeutrinoApp::getInstance()->timer_wakeup))) { + int otp = ::open("/proc/stb/cec/onetouchplay", O_WRONLY); + if (otp > -1) { + write(otp, g_settings.hdmi_cec_broadcast ? "f\n" : "0\n", 2); + close(otp); + } + } + } else { + if (g_settings.hdmi_cec_mode && g_settings.hdmi_cec_standby) { + int otp = ::open("/proc/stb/cec/systemstandby", O_WRONLY); + if (otp > -1) { + write(otp, g_settings.hdmi_cec_broadcast ? "f\n" : "0\n", 2); + close(otp); + } + } + } +} +#else void CCECSetup::setCECSettings() { printf("[neutrino CEC Settings] %s init CEC settings...\n", __FUNCTION__); @@ -124,9 +178,21 @@ void CCECSetup::setCECSettings() videoDecoder->SetCECAutoView(g_settings.hdmi_cec_view_on == 1); videoDecoder->SetCECMode((VIDEO_HDMI_CEC_MODE)g_settings.hdmi_cec_mode); } +#endif bool CCECSetup::changeNotify(const neutrino_locale_t OptionName, void * /*data*/) { +#if HAVE_SH4_HARDWARE + if (ARE_LOCALES_EQUAL(OptionName, LOCALE_VIDEOMENU_HDMI_CEC_MODE)) + { + printf("[neutrino CEC Settings] %s set CEC settings...\n", __FUNCTION__); + cec1->setActive(g_settings.hdmi_cec_mode != 0); + cec2->setActive(g_settings.hdmi_cec_mode != 0); + CKernelOptions ko; + ko.Enable("cec", g_settings.hdmi_cec_mode != 0); + g_settings.hdmi_cec_mode = ko.isEnabled("cec"); + } +#else if (ARE_LOCALES_EQUAL(OptionName, LOCALE_VIDEOMENU_HDMI_CEC_MODE)) { @@ -146,6 +212,7 @@ bool CCECSetup::changeNotify(const neutrino_locale_t OptionName, void * /*data*/ { videoDecoder->SetCECAutoView(g_settings.hdmi_cec_view_on == 1); } +#endif return false; } diff --git a/src/gui/cec_setup.h b/src/gui/cec_setup.h index c5aa3f1b5..4c41de252 100644 --- a/src/gui/cec_setup.h +++ b/src/gui/cec_setup.h @@ -46,7 +46,11 @@ class CCECSetup : public CMenuTarget, CChangeObserver public: CCECSetup(); ~CCECSetup(); +#if HAVE_SH4_HARDWARE + void setCECSettings(bool); +#else void setCECSettings(); +#endif int exec(CMenuTarget* parent, const std::string & actionKey); virtual bool changeNotify(const neutrino_locale_t OptionName, void * data); }; diff --git a/src/gui/channellist.cpp b/src/gui/channellist.cpp index 03a84868c..c41be3b41 100644 --- a/src/gui/channellist.cpp +++ b/src/gui/channellist.cpp @@ -967,7 +967,7 @@ int CChannelList::show() editMode(false); #ifdef ENABLE_GRAPHLCD - nGLCD::unlockChannel(); + cGLCD::unlockChannel(); #endif LCD4l->RemoveFile("/tmp/lcd/menu"); @@ -2252,7 +2252,7 @@ void CChannelList::updateVfd() #ifdef ENABLE_GRAPHLCD if(g_settings.glcd_enable) - nGLCD::lockChannel(g_Locale->getText(LOCALE_BOUQUETLIST_HEAD), chan->getName().c_str(), 0); + cGLCD::lockChannel(g_Locale->getText(LOCALE_BOUQUETLIST_HEAD), chan->getName().c_str(), 0); #endif if (g_settings.lcd4l_support) LCD4l->CreateFile("/tmp/lcd/menu", chan->getName().c_str(), g_settings.lcd4l_convert); diff --git a/src/gui/glcdsetup.cpp b/src/gui/glcdsetup.cpp index 6f26075d3..a87ae7a3e 100644 --- a/src/gui/glcdsetup.cpp +++ b/src/gui/glcdsetup.cpp @@ -30,12 +30,34 @@ #include #include #include -#include +#include #include #include #include "glcdsetup.h" #include +#include +#include +#include "glcdthemes.h" +#define ONOFFSEC_OPTION_COUNT 6 +static const CMenuOptionChooser::keyval ONOFFSEC_OPTIONS[ONOFFSEC_OPTION_COUNT] = { + { 0, LOCALE_OPTIONS_OFF }, + { 1, LOCALE_OPTIONS_ON }, + { 2, LOCALE_GLCD_STANDBY_LED_CLOCK }, + { 3, LOCALE_GLCD_STANDBY_LCD_CLOCK }, + { 4, LOCALE_GLCD_STANDBY_DIGITAL_CLOCK }, + { 5, LOCALE_GLCD_STANDBY_ANALOG_CLOCK } +}; + +#define ONOFFPRI_OPTION_COUNT 4 +static const CMenuOptionChooser::keyval ONOFFPRI_OPTIONS[ONOFFPRI_OPTION_COUNT] = { + { 0, LOCALE_GLCD_ALIGN_NONE }, + { 1, LOCALE_GLCD_ALIGN_LEFT }, + { 2, LOCALE_GLCD_ALIGN_CENTER }, + { 3, LOCALE_GLCD_ALIGN_RIGHT }, +}; + +#if 0 #define KEY_GLCD_BLACK 0 #define KEY_GLCD_WHITE 1 #define KEY_GLCD_RED 2 @@ -120,6 +142,7 @@ int GLCD_Menu::color2index(uint32_t color) { uint32_t GLCD_Menu::index2color(int i) { return (i < GLCD_COLOR_OPTION_COUNT) ? colormap[i] : GLCD::cColor::ERRCOL; } +#endif GLCD_Menu::GLCD_Menu() { @@ -130,37 +153,57 @@ GLCD_Menu::GLCD_Menu() int GLCD_Menu::exec(CMenuTarget* parent, const std::string & actionKey) { int res = menu_return::RETURN_REPAINT; - nGLCD *nglcd = nGLCD::getInstance(); + cGLCD *cglcd = cGLCD::getInstance(); + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + if(parent) + parent->hide(); if(actionKey == "rescan") { - nglcd->Rescan(); + cglcd->Rescan(); return res; } +#if 0 if(actionKey == "select_driver") { if(parent) parent->hide(); GLCD_Menu_Select_Driver(); - nglcd->Exit(); + cglcd->Exit(); return menu_return::RETURN_EXIT; } +#endif if(actionKey == "select_font") { - if(parent) - parent->hide(); CFileBrowser fileBrowser; CFileFilter fileFilter; fileFilter.addFilter("ttf"); fileBrowser.Filter = &fileFilter; if (fileBrowser.exec(FONTDIR) == true) { - g_settings.glcd_font = fileBrowser.getSelectedFile()->Name; - nglcd->Rescan(); + t.glcd_font = fileBrowser.getSelectedFile()->Name; + cglcd->Rescan(); } return res; + } else if (actionKey == "theme_settings") { + GLCD_Theme_Settings(); + return res; + } else if (actionKey == "brightness_default") { + g_settings.glcd_brightness = GLCD_DEFAULT_BRIGHTNESS; + g_settings.glcd_brightness_standby = GLCD_DEFAULT_BRIGHTNESS_STANDBY; + g_settings.glcd_brightness_dim = GLCD_DEFAULT_BRIGHTNESS_DIM; + g_settings.glcd_brightness_dim_time = GLCD_DEFAULT_BRIGHTNESS_DIM_TIME; + cglcd->UpdateBrightness(); + return res; + } else if (actionKey == "brightness_settings") { + GLCD_Brightness_Settings(); + return res; + } else if (actionKey == "standby_settings") { + GLCD_Standby_Settings(); + return res; + } else if (actionKey == "position_settings") { + GLCD_Theme_Position_Settings(); + return res; + } else { + GLCD_Menu_Settings(); + return res; } - if (parent) - parent->hide(); - - GLCD_Menu_Settings(); - return res; } @@ -172,155 +215,307 @@ bool GLCD_Menu::changeNotify (const neutrino_locale_t OptionName, void *Data) { if (!Data) return false; - nGLCD *nglcd = nGLCD::getInstance(); + cGLCD *cglcd = cGLCD::getInstance(); + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; switch(OptionName) { case LOCALE_GLCD_SELECT_FG: - g_settings.glcd_color_fg = GLCD_Menu::index2color(*((int *) Data)); - break; case LOCALE_GLCD_SELECT_BG: - g_settings.glcd_color_bg = GLCD_Menu::index2color(*((int *) Data)); - break; case LOCALE_GLCD_SELECT_BAR: - g_settings.glcd_color_bar = GLCD_Menu::index2color(*((int *) Data)); + cglcd->Update(); break; case LOCALE_GLCD_ENABLE: if (g_settings.glcd_enable) - nglcd->Resume(); + cglcd->Resume(); else - nglcd->Suspend(); + cglcd->Suspend(); return true; case LOCALE_GLCD_MIRROR_OSD: - nglcd->MirrorOSD(*((int *) Data)); + cglcd->MirrorOSD(*((int *) Data)); break; case LOCALE_GLCD_MIRROR_VIDEO: - nglcd->Update(); + cglcd->Update(); break; case LOCALE_GLCD_BRIGHTNESS: case LOCALE_GLCD_BRIGHTNESS_STANDBY: + case LOCALE_GLCD_BRIGHTNESS_DIM: + case LOCALE_GLCD_BRIGHTNESS_DIM_TIME: + cglcd->Update(); + break; + case LOCALE_GLCD_SHOW_PROGRESSBAR: + case LOCALE_GLCD_SHOW_DURATION: + case LOCALE_GLCD_SHOW_START: + case LOCALE_GLCD_SHOW_END: + case LOCALE_GLCD_SHOW_TIME: + case LOCALE_GLCD_SHOW_WEATHER: case LOCALE_GLCD_SHOW_LOGO: case LOCALE_GLCD_SIZE_BAR: + case LOCALE_GLCD_BAR_X_POSITION: + case LOCALE_GLCD_BAR_Y_POSITION: + case LOCALE_GLCD_BAR_WIDTH: case LOCALE_GLCD_SIZE_CHANNEL: + case LOCALE_GLCD_CHANNEL_X_POSITION: + case LOCALE_GLCD_CHANNEL_Y_POSITION: case LOCALE_GLCD_SIZE_EPG: + case LOCALE_GLCD_EPG_X_POSITION: + case LOCALE_GLCD_EPG_Y_POSITION: + case LOCALE_GLCD_SIZE_DURATION: + case LOCALE_GLCD_DURATION_X_POSITION: + case LOCALE_GLCD_DURATION_Y_POSITION: + case LOCALE_GLCD_SIZE_START: + case LOCALE_GLCD_START_X_POSITION: + case LOCALE_GLCD_START_Y_POSITION: + case LOCALE_GLCD_SIZE_END: + case LOCALE_GLCD_END_X_POSITION: + case LOCALE_GLCD_END_Y_POSITION: case LOCALE_GLCD_SIZE_LOGO: + case LOCALE_GLCD_LOGO_X_POSITION: + case LOCALE_GLCD_LOGO_Y_POSITION: case LOCALE_GLCD_SIZE_TIME: - case LOCALE_GLCD_SIZE_TIME_STANDBY: + case LOCALE_GLCD_TIME_X_POSITION: + case LOCALE_GLCD_TIME_Y_POSITION: case LOCALE_GLCD_TIME_IN_STANDBY: case LOCALE_GLCD_SCROLL_SPEED: + case LOCALE_GLCD_THEME_POSITION_SETTINGS: break; default: return false; } - if (((OptionName == LOCALE_GLCD_TIME_IN_STANDBY || OptionName == LOCALE_GLCD_BRIGHTNESS_STANDBY) && g_settings.glcd_percent_time_standby) || OptionName == LOCALE_GLCD_SIZE_TIME_STANDBY) - nglcd->StandbyMode(true); - else - nglcd->StandbyMode(false); - nglcd->Update(); + if (OptionName == LOCALE_GLCD_TIME_IN_STANDBY || OptionName == LOCALE_GLCD_BRIGHTNESS_STANDBY || OptionName == LOCALE_GLCD_STANDBY_LED_CLOCK || OptionName == LOCALE_GLCD_STANDBY_LCD_CLOCK + || OptionName == LOCALE_GLCD_STANDBY_DIGITAL_CLOCK || OptionName == LOCALE_GLCD_STANDBY_DIGITAL_CLOCK || OptionName == LOCALE_GLCD_STANDBY_ANALOG_CLOCK || OptionName == LOCALE_GLCD_STANDBY_WEATHER + || OptionName == LOCALE_GLCD_DIGITAL_CLOCK_Y_POSITION || OptionName == LOCALE_GLCD_SIZE_SIMPLE_CLOCK || OptionName == LOCALE_GLCD_SIMPLE_CLOCK_Y_POSITION) + cglcd->StandbyMode(true); + else + cglcd->StandbyMode(false); + + cglcd->Update(); return true; } -static const CMenuOptionChooser::keyval GLCD_CLOCK_OPTIONS[] = { - { nGLCD::CLOCK_OFF, LOCALE_OPTIONS_OFF }, - { nGLCD::CLOCK_DIGITAL_HM, LOCALE_GLCD_CLOCK_DIGITAL_HM }, -// { nGLCD::CLOCK_DIGITAL_HMS, LOCALE_GLCD_CLOCK_DIGITAL_HMS }, -// { nGLCD::CLOCK_ANALOG, LOCALE_GLCD_CLOCK_ANALOG } -}; -#define GLCD_CLOCK_OPTIONS_COUNT (sizeof(GLCD_CLOCK_OPTIONS)/sizeof(CMenuOptionChooser::keyval)) - void GLCD_Menu::GLCD_Menu_Settings() { - int color_bg = color2index(g_settings.glcd_color_bg); - int color_fg = color2index(g_settings.glcd_color_fg); - int color_bar = color2index(g_settings.glcd_color_bar); - CMenuWidget m(LOCALE_GLCD_HEAD, NEUTRINO_ICON_SETTINGS, width); m.addIntroItems(); m.setSelected(selected); + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + sigc::slot0 slot_repaint = sigc::mem_fun(m, &CMenuWidget::paint); //we want to repaint after changed Option + m.addItem(new CMenuOptionChooser(LOCALE_GLCD_ENABLE, &g_settings.glcd_enable, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, this)); - - m.addItem(new CMenuForwarder(LOCALE_GLCD_DISPLAY, (nGLCD::getInstance()->GetConfigSize() > 1), - nGLCD::getInstance()->GetConfigName(g_settings.glcd_selected_config).c_str(), this, "select_driver")); int shortcut = 1; m.addItem(GenericMenuSeparatorLine); - m.addItem(new CMenuOptionChooser(LOCALE_GLCD_SELECT_FG, &color_fg, - GLCD_COLOR_OPTIONS, GLCD_COLOR_OPTION_COUNT, true, this, - CRCInput::convertDigitToKey(shortcut++), NULL, true)); - m.addItem(new CMenuOptionChooser(LOCALE_GLCD_SELECT_BG, &color_bg, - GLCD_COLOR_OPTIONS, GLCD_COLOR_OPTION_COUNT, true, this, - CRCInput::convertDigitToKey(shortcut++), NULL, true)); - m.addItem(new CMenuOptionChooser(LOCALE_GLCD_SELECT_BAR, &color_bar, - GLCD_COLOR_OPTIONS, GLCD_COLOR_OPTION_COUNT, true, this, + m.addItem(new CMenuForwarder(LOCALE_GLCD_THEME_SETTINGS, true, NULL, this, "theme_settings", CRCInput::convertDigitToKey(shortcut++))); - m.addItem(new CMenuForwarder(LOCALE_GLCD_FONT, true, g_settings.glcd_font, this, "select_font", - CRCInput::convertDigitToKey(shortcut++))); - m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_SIZE_CHANNEL, - &g_settings.glcd_percent_channel, true, 0, 100, this)); - m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_SIZE_EPG, - &g_settings.glcd_percent_epg, true, 0, 100, this)); - m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_SIZE_BAR, - &g_settings.glcd_percent_bar, true, 0, 100, this)); - m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_SIZE_TIME, - &g_settings.glcd_percent_time, true, 0, 100, this)); - m.addItem(new CMenuOptionChooser(LOCALE_GLCD_SHOW_LOGO, &g_settings.glcd_show_logo, - OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, this, - CRCInput::convertDigitToKey(shortcut++))); - m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_SIZE_LOGO, - &g_settings.glcd_percent_logo, true, 0, 100, this)); - m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_BRIGHTNESS, - &g_settings.glcd_brightness, true, 0, 100, this)); m.addItem(GenericMenuSeparatorLine); - m.addItem(new CMenuOptionChooser(LOCALE_GLCD_TIME_IN_STANDBY, &g_settings.glcd_time_in_standby, - GLCD_CLOCK_OPTIONS, GLCD_CLOCK_OPTIONS_COUNT, true, this, + m.addItem(new CMenuForwarder(LOCALE_GLCD_BRIGHTNESS_SETTINGS, true, NULL, this, "brightness_settings", + CRCInput::convertDigitToKey(shortcut++))); + m.addItem(GenericMenuSeparatorLine); + m.addItem(new CMenuForwarder(LOCALE_GLCD_STANDBY_SETTINGS, true, NULL, this, "standby_settings", CRCInput::convertDigitToKey(shortcut++))); - m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_SIZE_TIME_STANDBY, - &g_settings.glcd_percent_time_standby, true, 0, 100, this)); - m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_BRIGHTNESS_STANDBY, - &g_settings.glcd_brightness_standby, true, 0, 100, this)); m.addItem(GenericMenuSeparatorLine); m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_SCROLL_SPEED, &g_settings.glcd_scroll_speed, true, 1, 63, this)); m.addItem(GenericMenuSeparatorLine); + m.addItem(new CMenuOptionChooser(LOCALE_GLCD_SHOW_LOGO, &g_settings.glcd_show_logo, + OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, this, + CRCInput::convertDigitToKey(shortcut++))); + m.addItem(GenericMenuSeparatorLine); m.addItem(new CMenuOptionChooser(LOCALE_GLCD_MIRROR_OSD, &g_settings.glcd_mirror_osd, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, this, CRCInput::RC_green)); m.addItem(new CMenuOptionChooser(LOCALE_GLCD_MIRROR_VIDEO, &g_settings.glcd_mirror_video, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, this, CRCInput::RC_yellow)); m.addItem(GenericMenuSeparatorLine); - m.addItem(new CMenuForwarder(LOCALE_GLCD_RESTART, true, NULL, this, "rescan", CRCInput::RC_red)); + m.addItem(new CMenuForwarder(LOCALE_GLCD_RESTART, true, NULL, this, "rescan", CRCInput::RC_blue)); + m.exec(NULL, ""); selected = m.getSelected(); - nGLCD::getInstance()->StandbyMode(false); + cGLCD::getInstance()->StandbyMode(false); m.hide(); } -void GLCD_Menu::GLCD_Menu_Select_Driver() +void GLCD_Menu::GLCD_Standby_Settings() { - int select = 0; + CMenuWidget m(LOCALE_GLCD_STANDBY_SETTINGS, NEUTRINO_ICON_SETTINGS, width); + m.addIntroItems(); + m.setSelected(selected); - if (nGLCD::getInstance()->GetConfigSize() > 1) - { - CMenuWidget *m = new CMenuWidget(LOCALE_GLCD_HEAD, NEUTRINO_ICON_SETTINGS); - CMenuSelectorTarget * selector = new CMenuSelectorTarget(&select); + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + sigc::slot0 slot_repaint = sigc::mem_fun(m, &CMenuWidget::paint); //we want to repaint after changed Option - // we don't show introitems, so we add a separator for a smoother view - m->addItem(GenericMenuSeparator); - - CMenuForwarder* mf; - for (int i = 0; i < nGLCD::getInstance()->GetConfigSize(); i++) - { - mf = new CMenuForwarder(nGLCD::getInstance()->GetConfigName(i), true, NULL, selector,to_string(i).c_str()); - m->addItem(mf); - } - - m->enableSaveScreen(); - m->exec(NULL, ""); - - if (!m->gotAction()) - return; - - delete selector; - m->hide(); + int shortcut = 1; + m.addItem(new CMenuOptionChooser(LOCALE_GLCD_TIME_IN_STANDBY, &g_settings.glcd_time_in_standby, + ONOFFSEC_OPTIONS, ONOFFSEC_OPTION_COUNT, true, this, + CRCInput::convertDigitToKey(shortcut++))); + m.addItem(new CMenuOptionChooser(LOCALE_GLCD_STANDBY_WEATHER, &g_settings.glcd_standby_weather, + OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, this)); + if (t.glcd_position_settings) { + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_DIGITAL_CLOCK_Y_POSITION, + &t.glcd_digital_clock_y_position, true, 0, 500, this)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_SIZE_SIMPLE_CLOCK, + &t.glcd_size_simple_clock, true, 0, 100, this)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_SIMPLE_CLOCK_Y_POSITION, + &t.glcd_simple_clock_y_position, true, 0, 500, this)); } - g_settings.glcd_selected_config = select; + m.exec(NULL, ""); + selected = m.getSelected(); + cGLCD::getInstance()->StandbyMode(false); + m.hide(); +} + +void GLCD_Menu::GLCD_Brightness_Settings() +{ + CMenuWidget m(LOCALE_GLCD_BRIGHTNESS_SETTINGS, NEUTRINO_ICON_SETTINGS, width); + m.addIntroItems(); + m.setSelected(selected); + + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + sigc::slot0 slot_repaint = sigc::mem_fun(m, &CMenuWidget::paint); //we want to repaint after changed Option + + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_BRIGHTNESS, + &g_settings.glcd_brightness, true, 0, 10, this, CRCInput::RC_nokey, NULL, 0, 0, NONEXISTANT_LOCALE, true)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_BRIGHTNESS_STANDBY, + &g_settings.glcd_brightness_standby, true, 0, 10, this, CRCInput::RC_nokey, NULL, 0, 0, NONEXISTANT_LOCALE, true)); + m.addItem(GenericMenuSeparatorLine); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_BRIGHTNESS_DIM, + &g_settings.glcd_brightness_dim, true, 0, 10, this, CRCInput::RC_nokey, NULL, 0, 0, NONEXISTANT_LOCALE, true)); + CStringInput *dim_time = new CStringInput(LOCALE_GLCD_BRIGHTNESS_DIM_TIME, &g_settings.glcd_brightness_dim_time, 5, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE,"0123456789 "); + m.addItem(new CMenuForwarder(LOCALE_GLCD_BRIGHTNESS_DIM_TIME, true, g_settings.glcd_brightness_dim_time, dim_time)); + + m.addItem(GenericMenuSeparatorLine); + m.addItem(new CMenuForwarder(LOCALE_OPTIONS_DEFAULT, true, NULL, this, "brightness_default", CRCInput::RC_nokey)); + + m.exec(NULL, ""); + selected = m.getSelected(); + cGLCD::getInstance()->StandbyMode(false); + m.hide(); +} + +void GLCD_Menu::GLCD_Theme_Settings() +{ + CMenuWidget m(LOCALE_GLCD_THEME_SETTINGS, NEUTRINO_ICON_SETTINGS, width); + m.addIntroItems(); + m.setSelected(selected); + + int shortcut = 1; + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + sigc::slot0 slot_repaint = sigc::mem_fun(m, &CMenuWidget::paint); //we want to repaint after changed Option + + m.addItem(new CMenuForwarder(LOCALE_GLCD_THEME, true, NULL, CGLCDThemes::getInstance(), NULL, CRCInput::convertDigitToKey(shortcut++))); + + m.addItem(new CMenuForwarder(LOCALE_GLCD_FONT, true, t.glcd_font, this, "select_font", + CRCInput::convertDigitToKey(shortcut++))); + + m.addItem(GenericMenuSeparatorLine); + CColorSetupNotifier *colorSetupNotifier = new CColorSetupNotifier(); + + CColorChooser* fg = new CColorChooser(LOCALE_GLCD_SELECT_FG, &t.glcd_color_fg_red, &t.glcd_color_fg_green, &t.glcd_color_fg_blue, NULL, colorSetupNotifier); + m.addItem(new CMenuDForwarder(LOCALE_GLCD_SELECT_FG, true, NULL, fg)); + + CColorChooser* bg = new CColorChooser(LOCALE_GLCD_SELECT_BG, &t.glcd_color_bg_red, &t.glcd_color_bg_green, &t.glcd_color_bg_blue, NULL, colorSetupNotifier); + m.addItem(new CMenuDForwarder(LOCALE_GLCD_SELECT_BG, true, NULL, bg)); + + CColorChooser* bar = new CColorChooser(LOCALE_GLCD_SELECT_BAR, &t.glcd_color_bar_red, &t.glcd_color_bar_green, &t.glcd_color_bar_blue, NULL, colorSetupNotifier); + m.addItem(new CMenuDForwarder(LOCALE_GLCD_SELECT_BAR, true, NULL, bar)); + + if (t.glcd_position_settings) + m.addItem(new CMenuForwarder(LOCALE_GLCD_POSITION_SETTINGS, true, NULL, this, "position_settings", + CRCInput::convertDigitToKey(shortcut++))); + + //delete colorSetupNotifier; + m.exec(NULL, ""); + selected = m.getSelected(); + cGLCD::getInstance()->StandbyMode(false); + m.hide(); +} + +void GLCD_Menu::GLCD_Theme_Position_Settings() +{ + CMenuWidget m(LOCALE_GLCD_THEME_POSITION_SETTINGS, NEUTRINO_ICON_SETTINGS, width); + m.addIntroItems(); + m.setSelected(selected); + + SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + sigc::slot0 slot_repaint = sigc::mem_fun(m, &CMenuWidget::paint); //we want to repaint after changed Option + + m.addItem(new CMenuOptionChooser(LOCALE_GLCD_SHOW_PROGRESSBAR, &t.glcd_show_progressbar, + OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, this)); + m.addItem(new CMenuOptionChooser(LOCALE_GLCD_SHOW_DURATION, &t.glcd_show_duration, + OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, this)); + m.addItem(new CMenuOptionChooser(LOCALE_GLCD_SHOW_START, &t.glcd_show_start, + OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, this)); + m.addItem(new CMenuOptionChooser(LOCALE_GLCD_SHOW_END, &t.glcd_show_end, + OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, this)); + m.addItem(new CMenuOptionChooser(LOCALE_GLCD_SHOW_TIME, &t.glcd_show_time, + OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, this)); + m.addItem(new CMenuOptionChooser(LOCALE_GLCD_SHOW_WEATHER, &t.glcd_show_weather, + OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, this)); + m.addItem(GenericMenuSeparatorLine); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_SIZE_CHANNEL, + &t.glcd_percent_channel, true, 0, 100, this)); + m.addItem(new CMenuOptionChooser(LOCALE_GLCD_ALIGN_CHANNEL, &t.glcd_align_channel, + ONOFFPRI_OPTIONS, ONOFFPRI_OPTION_COUNT, true, NULL)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_CHANNEL_X_POSITION, + &t.glcd_channel_x_position, true, 0, 500, this)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_CHANNEL_Y_POSITION, + &t.glcd_channel_y_position, true, 0, 500, this)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_SIZE_EPG, + &t.glcd_percent_epg, true, 0, 100, this)); + m.addItem(new CMenuOptionChooser(LOCALE_GLCD_ALIGN_EPG, &t.glcd_align_epg, + ONOFFPRI_OPTIONS, ONOFFPRI_OPTION_COUNT, true, NULL)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_EPG_X_POSITION, + &t.glcd_epg_x_position, true, 0, 500, this)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_EPG_Y_POSITION, + &t.glcd_epg_y_position, true, 0, 500, this)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_SIZE_DURATION, + &t.glcd_percent_duration, true, 0, 100, this)); + m.addItem(new CMenuOptionChooser(LOCALE_GLCD_ALIGN_DURATION, &t.glcd_align_duration, + ONOFFPRI_OPTIONS, ONOFFPRI_OPTION_COUNT, true, this, NULL)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_DURATION_X_POSITION, + &t.glcd_duration_x_position, true, 0, 500, this)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_DURATION_Y_POSITION, + &t.glcd_duration_y_position, true, 0, 500, this)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_SIZE_START, + &t.glcd_percent_start, true, 0, 100, this)); + m.addItem(new CMenuOptionChooser(LOCALE_GLCD_ALIGN_START, &t.glcd_align_start, + ONOFFPRI_OPTIONS, ONOFFPRI_OPTION_COUNT, true, NULL)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_START_X_POSITION, + &t.glcd_start_x_position, true, 0, 500, this)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_START_Y_POSITION, + &t.glcd_start_y_position, true, 0, 500, this)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_SIZE_END, + &t.glcd_percent_end, true, 0, 100, this)); + m.addItem(new CMenuOptionChooser(LOCALE_GLCD_ALIGN_END, &t.glcd_align_end, + ONOFFPRI_OPTIONS, ONOFFPRI_OPTION_COUNT, true, NULL)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_END_X_POSITION, + &t.glcd_end_x_position, true, 0, 500, this)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_END_Y_POSITION, + &t.glcd_end_y_position, true, 0, 500, this)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_SIZE_TIME, + &t.glcd_percent_time, true, 0, 100, this)); + m.addItem(new CMenuOptionChooser(LOCALE_GLCD_ALIGN_TIME, &t.glcd_align_time, + ONOFFPRI_OPTIONS, ONOFFPRI_OPTION_COUNT, true, NULL)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_TIME_X_POSITION, + &t.glcd_time_x_position, true, 0, 500, this)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_TIME_Y_POSITION, + &t.glcd_time_y_position, true, 0, 500, this)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_SIZE_BAR, + &t.glcd_percent_bar, true, 0, 100, this)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_BAR_X_POSITION, + &t.glcd_bar_x_position, true, 0, 500, this)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_BAR_Y_POSITION, + &t.glcd_bar_y_position, true, 0, 500, this)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_BAR_WIDTH, + &t.glcd_bar_width, true, 0, 500, this)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_SIZE_LOGO, + &t.glcd_percent_logo, true, 0, 100, this)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_LOGO_X_POSITION, + &t.glcd_logo_x_position, true, 0, 500, this)); + m.addItem(new CMenuOptionNumberChooser(LOCALE_GLCD_LOGO_Y_POSITION, + &t.glcd_logo_y_position, true, 0, 500, this)); + + m.exec(NULL, ""); + selected = m.getSelected(); + cGLCD::getInstance()->StandbyMode(false); + m.hide(); } diff --git a/src/gui/glcdsetup.h b/src/gui/glcdsetup.h index b9cb9c0ab..54a1994f9 100644 --- a/src/gui/glcdsetup.h +++ b/src/gui/glcdsetup.h @@ -28,22 +28,26 @@ #include #include #include -#include +#include +#include +#include class GLCD_Menu : public CMenuTarget, public CChangeObserver { private: int width; int selected; - static int color2index(uint32_t color); - void GLCD_Menu_Select_Driver(); + SNeutrinoGlcdTheme oldTheme; public: - static uint32_t index2color(int i); GLCD_Menu(); void hide(); int exec(CMenuTarget* parent, const std::string & actionKey); bool changeNotify(const neutrino_locale_t, void *); void GLCD_Menu_Settings(); + void GLCD_Standby_Settings(); + void GLCD_Brightness_Settings(); + void GLCD_Theme_Settings(); + void GLCD_Theme_Position_Settings(); }; #endif // __glcdsetup_h__ #endif // ENABLE_GRAPHLCD diff --git a/src/gui/glcdthemes.cpp b/src/gui/glcdthemes.cpp new file mode 100644 index 000000000..ffa30a2b7 --- /dev/null +++ b/src/gui/glcdthemes.cpp @@ -0,0 +1,474 @@ +/* + $port: themes.cpp,v 1.16 2010/09/05 21:27:44 tuxbox-cvs Exp $ + + Neutrino-GUI - DBoxII-Project + + License: GPL + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + Copyright (C) 2007, 2008, 2009 (flasher) Frank Liebelt + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "widget/menue.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "glcdthemes.h" + +#define USERDIR "/var" THEMESDIR +#define FILE_SUFFIX ".otheme" + +static SNeutrinoGlcdTheme &t = g_settings.glcd_theme; + +CGLCDThemes::CGLCDThemes() +: themefile('\t') +{ + width = 40; + + hasThemeChanged = false; +} + +CGLCDThemes* CGLCDThemes::getInstance() +{ + static CGLCDThemes* th = NULL; + + if(!th) { + th = new CGLCDThemes(); + dprintf(DEBUG_DEBUG, "CGLCDThemes Instance created\n"); + } + return th; +} + +int CGLCDThemes::exec(CMenuTarget* parent, const std::string & actionKey) +{ + int res = menu_return::RETURN_REPAINT; + + if( !actionKey.empty() ) + { + if (actionKey=="default_theme") + { + if(!applyDefaultTheme()) + setupDefaultColors(); // fallback + changeNotify(NONEXISTANT_LOCALE, NULL); + } + else + { + std::string themeFile = actionKey; + if ( strstr(themeFile.c_str(), "{U}") != 0 ) + { + themeFile.erase(0, 3); + readFile(((std::string)THEMESDIR_VAR + "/" + themeFile + FILE_SUFFIX).c_str()); + } + else + readFile(((std::string)THEMESDIR + "/" + themeFile + FILE_SUFFIX).c_str()); + g_settings.glcd_theme_name = themeFile; + } + OnAfterSelectTheme(); + CFrameBuffer::getInstance()->clearIconCache(); + return res; + } + + + if (parent) + parent->hide(); + + if ( !hasThemeChanged ) + rememberOldTheme( true ); + + return Show(); +} + +void CGLCDThemes::initThemesMenu(CMenuWidget &themes) +{ + struct dirent **themelist; + int n; + const char *pfade[] = {THEMESDIR, THEMESDIR_VAR}; + bool hasCVSThemes, hasUserThemes; + hasCVSThemes = hasUserThemes = false; + std::string userThemeFile = ""; + CMenuForwarder* oj; + + // only to visualize if we have a migrated theme + if (g_settings.glcd_theme_name.empty() || g_settings.glcd_theme_name == MIGRATE_THEME_OLED_NAME) + { + themes.addItem(new CMenuSeparator(CMenuSeparator::LINE)); + themes.addItem(new CMenuForwarder(MIGRATE_THEME_OLED_NAME, false, "", this)); + } + + for(int p = 0;p < 2;p++) + { + n = scandir(pfade[p], &themelist, 0, alphasort); + if(n < 0) + perror("loading glcd themes: scandir"); + else + { + for(int count=0;countd_name; + char *pos = strstr(file, ".otheme"); + if(pos != NULL) + { + if ( p == 0 && hasCVSThemes == false ) { + themes.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_COLORTHEMEMENU_SELECT2)); + hasCVSThemes = true; + } else if ( p == 1 && hasUserThemes == false ) { + themes.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_COLORTHEMEMENU_SELECT1)); + hasUserThemes = true; + } + *pos = '\0'; + if ( p == 1 ) { + userThemeFile = "{U}" + (std::string)file; + oj = new CMenuForwarder(file, true, "", this, userThemeFile.c_str()); + } else + oj = new CMenuForwarder(file, true, "", this, file); + + themes.addItem( oj ); + } + free(themelist[count]); + } + free(themelist); + } + } + + //on first paint exec this methode to set marker to item + markSelectedTheme(&themes); + + //for all next menu paints markers are setted with this slot inside exec() + if (OnAfterSelectTheme.empty()) + OnAfterSelectTheme.connect(sigc::bind(sigc::mem_fun(this, &CGLCDThemes::markSelectedTheme), &themes)); +} + +int CGLCDThemes::Show() +{ + move_userDir(); + + std::string file_name = ""; + + CMenuWidget themes (LOCALE_COLORMENU_MENUCOLORS, NEUTRINO_ICON_SETTINGS, width); + sigc::slot0 slot_repaint = sigc::mem_fun(themes, &CMenuWidget::hide); //we want to clean screen before repaint after changed Option + themes.OnBeforePaint.connect(slot_repaint); + + themes.addIntroItems(LOCALE_COLORTHEMEMENU_HEAD2); + + //set default theme + std::string default_theme = DEFAULT_OLED_THEME; + CMenuForwarder* fw = new CMenuForwarder(LOCALE_COLORTHEMEMENU_NEUTRINO_THEME, true, default_theme.c_str(), this, "default_theme", CRCInput::RC_red); + themes.addItem(fw); + fw->setHint("", LOCALE_COLORTHEMEMENU_NEUTRINO_THEME_HINT); + + initThemesMenu(themes); + + CKeyboardInput nameInput(LOCALE_COLORTHEMEMENU_NAME, &file_name); + CMenuForwarder *m1 = new CMenuForwarder(LOCALE_COLORTHEMEMENU_SAVE, true , NULL, &nameInput, NULL, CRCInput::RC_green); + + if (!CFileHelpers::createDir(THEMESDIR_VAR)) { + printf("[neutrino glcd theme] error creating %s\n", THEMESDIR_VAR); + } + + if (access(THEMESDIR_VAR, F_OK) == 0 ) { + themes.addItem(GenericMenuSeparatorLine); + themes.addItem(m1); + } else { + delete m1; + printf("[neutrino glcd theme] error accessing %s\n", THEMESDIR_VAR); + } + + int res = themes.exec(NULL, ""); + + if (!file_name.empty()) { + saveFile(((std::string)THEMESDIR_VAR + "/" + file_name + FILE_SUFFIX).c_str()); + } + + if (hasThemeChanged) { + if (ShowMsg(LOCALE_MESSAGEBOX_INFO, LOCALE_COLORTHEMEMENU_QUESTION, CMsgBox::mbrYes, CMsgBox::mbYes | CMsgBox::mbNo, NEUTRINO_ICON_SETTINGS) != CMsgBox::mbrYes) + rememberOldTheme( false ); + else + hasThemeChanged = false; + } + return res; +} + +void CGLCDThemes::rememberOldTheme(bool remember) +{ + if ( remember ) { + oldTheme = t; + oldTheme_name = g_settings.glcd_theme_name; + } else { + t = oldTheme; + g_settings.glcd_theme_name = oldTheme_name; + + changeNotify(NONEXISTANT_LOCALE, NULL); + hasThemeChanged = false; + } +} + +void CGLCDThemes::readFile(const char *themename) +{ + if(themefile.loadConfig(themename)) + { + getTheme(themefile); + + changeNotify(NONEXISTANT_LOCALE, NULL); + hasThemeChanged = true; + } + else + printf("[neutrino glcd theme] %s not found\n", themename); +} + +void CGLCDThemes::saveFile(const char *themename) +{ + setTheme(themefile); + + if (themefile.getModifiedFlag()){ + printf("[neutrino glcd theme] save theme into %s\n", themename); + if (!themefile.saveConfig(themename)) + printf("[neutrino glcd theme] %s write error\n", themename); + } +} + +bool CGLCDThemes::applyDefaultTheme() +{ + g_settings.glcd_theme_name = DEFAULT_OLED_THEME; + std::string default_theme = THEMESDIR "/" + g_settings.glcd_theme_name + ".otheme"; + if(themefile.loadConfig(default_theme)){ + getTheme(themefile); + return true; + } + dprintf(DEBUG_NORMAL, "[CGLCDThemes]\t[%s - %d], No default theme found, creating migrated theme from current theme settings\n", __func__, __LINE__); + return false; +} + +// setup default Colors +void CGLCDThemes::setupDefaultColors() +{ + CConfigFile empty(':'); + getTheme(empty); +} + +void CGLCDThemes::setTheme(CConfigFile &configfile) +{ + configfile.setInt32("glcd_color_fg_red", t.glcd_color_fg_red); + configfile.setInt32("glcd_color_fg_green", t.glcd_color_fg_green); + configfile.setInt32("glcd_color_fg_blue", t.glcd_color_fg_blue); + configfile.setInt32("glcd_color_bg_red", t.glcd_color_bg_red); + configfile.setInt32("glcd_color_bg_green", t.glcd_color_bg_green); + configfile.setInt32("glcd_color_bg_blue", t.glcd_color_bg_blue); + configfile.setInt32("glcd_color_bar_red", t.glcd_color_bar_red); + configfile.setInt32("glcd_color_bar_green", t.glcd_color_bar_green); + configfile.setInt32("glcd_color_bar_blue", t.glcd_color_bar_blue); + configfile.setString("glcd_font", t.glcd_font); + configfile.setString("glcd_background", t.glcd_background); + configfile.setBool("glcd_show_progressbar", t.glcd_show_progressbar); + configfile.setBool("glcd_show_duration", t.glcd_show_duration); + configfile.setBool("glcd_show_start", t.glcd_show_start); + configfile.setBool("glcd_show_end", t.glcd_show_end); + configfile.setBool("glcd_show_time", t.glcd_show_time); + configfile.setBool("glcd_show_weather", t.glcd_show_weather); + configfile.setInt32("glcd_align_channel", t.glcd_align_channel); + configfile.setInt32("glcd_align_epg", t.glcd_align_epg); + configfile.setInt32("glcd_align_duration", t.glcd_align_duration); + configfile.setInt32("glcd_align_start", t.glcd_align_start); + configfile.setInt32("glcd_align_end", t.glcd_align_end); + configfile.setInt32("glcd_align_time", t.glcd_align_time); + configfile.setInt32("glcd_percent_channel", t.glcd_percent_channel); + configfile.setInt32("glcd_channel_x_position", t.glcd_channel_x_position); + configfile.setInt32("glcd_channel_y_position", t.glcd_channel_y_position); + configfile.setInt32("glcd_percent_epg", t.glcd_percent_epg); + configfile.setInt32("glcd_epg_x_position", t.glcd_epg_x_position); + configfile.setInt32("glcd_epg_y_position", t.glcd_epg_y_position); + configfile.setInt32("glcd_percent_duration", t.glcd_percent_duration); + configfile.setInt32("glcd_duration_x_position", t.glcd_duration_x_position); + configfile.setInt32("glcd_duration_y_position", t.glcd_duration_y_position); + configfile.setInt32("glcd_percent_start", t.glcd_percent_start); + configfile.setInt32("glcd_start_x_position", t.glcd_start_x_position); + configfile.setInt32("glcd_start_y_position", t.glcd_start_y_position); + configfile.setInt32("glcd_percent_end", t.glcd_percent_end); + configfile.setInt32("glcd_end_x_position", t.glcd_end_x_position); + configfile.setInt32("glcd_end_y_position", t.glcd_end_y_position); + configfile.setInt32("glcd_percent_time", t.glcd_percent_time); + configfile.setInt32("glcd_time_x_position", t.glcd_time_x_position); + configfile.setInt32("glcd_time_y_position", t.glcd_time_y_position); + configfile.setInt32("glcd_percent_bar", t.glcd_percent_bar); + configfile.setInt32("glcd_bar_x_position", t.glcd_bar_x_position); + configfile.setInt32("glcd_bar_y_position", t.glcd_bar_y_position); + configfile.setInt32("glcd_bar_width", t.glcd_bar_width); + configfile.setInt32("glcd_percent_logo", t.glcd_percent_logo); + configfile.setInt32("glcd_logo_x_position", t.glcd_logo_x_position); + configfile.setInt32("glcd_logo_y_position", t.glcd_logo_y_position); + configfile.setInt32("glcd_percent_smalltext", t.glcd_percent_smalltext); + configfile.setInt32("glcd_smalltext_y_position", t.glcd_smalltext_y_position); + configfile.setInt32("glcd_rec_icon_x_position", t.glcd_rec_icon_x_position); + configfile.setInt32("glcd_mute_icon_x_position", t.glcd_mute_icon_x_position); + configfile.setInt32("glcd_ts_icon_x_position", t.glcd_ts_icon_x_position); + configfile.setInt32("glcd_timer_icon_x_position", t.glcd_timer_icon_x_position); + configfile.setInt32("glcd_ecm_icon_x_position", t.glcd_ecm_icon_x_position); + configfile.setInt32("glcd_dd_icon_x_position", t.glcd_dd_icon_x_position); + configfile.setInt32("glcd_txt_icon_x_position", t.glcd_txt_icon_x_position); + configfile.setInt32("glcd_cam_icon_x_position", t.glcd_cam_icon_x_position); + configfile.setInt32("glcd_digital_clock_y_position", t.glcd_digital_clock_y_position); + configfile.setInt32("glcd_size_simple_clock", t.glcd_size_simple_clock); + configfile.setInt32("glcd_simple_clock_y_position", t.glcd_simple_clock_y_position); + configfile.setInt32("glcd_weather_x_position_current", t.glcd_weather_x_position_current); + configfile.setInt32("glcd_weather_x_position_next", t.glcd_weather_x_position_next); + configfile.setInt32("glcd_weather_y_position", t.glcd_weather_y_position); + configfile.setInt32("glcd_weather_x_position_current_standby", t.glcd_weather_x_position_current_standby); + configfile.setInt32("glcd_weather_x_position_next_standby", t.glcd_weather_x_position_next_standby); + configfile.setInt32("glcd_weather_y_position_standby", t.glcd_weather_y_position_standby); + configfile.setInt32("glcd_position_settings", t.glcd_position_settings); +} + +void CGLCDThemes::getTheme(CConfigFile &configfile) +{ + t.glcd_color_fg_red = configfile.getInt32("glcd_color_fg_red", 0x00); + t.glcd_color_fg_green = configfile.getInt32("glcd_color_fg_green", 0x00); + t.glcd_color_fg_blue = configfile.getInt32("glcd_color_fg_blue", 0x00); + t.glcd_color_bg_red = configfile.getInt32("glcd_color_bg_red", 0x00); + t.glcd_color_bg_green = configfile.getInt32("glcd_color_bg_green", 0x00); + t.glcd_color_bg_blue = configfile.getInt32("glcd_color_bg_blue", 0x00); + t.glcd_color_bar_red = configfile.getInt32("glcd_color_bar_red", 0x00); + t.glcd_color_bar_green = configfile.getInt32("glcd_color_bar_green", 0x00); + t.glcd_color_bar_blue = configfile.getInt32("glcd_color_bar_blue", 0x00); + t.glcd_font = configfile.getString("glcd_font", ""); + t.glcd_background = configfile.getString("glcd_background", ""); + t.glcd_show_progressbar = configfile.getBool("glcd_show_progressbar", false); + t.glcd_show_duration = configfile.getBool("glcd_show_duration", false); + t.glcd_show_start = configfile.getBool("glcd_show_start", false); + t.glcd_show_end = configfile.getBool("glcd_show_end", false); + t.glcd_show_time = configfile.getBool("glcd_show_time", false); + t.glcd_show_weather = configfile.getBool("glcd_show_weather", false); + t.glcd_align_channel = configfile.getInt32("glcd_align_channel", 0); + t.glcd_align_epg = configfile.getInt32("glcd_align_epg", 0); + t.glcd_align_duration = configfile.getInt32("glcd_align_duration", 0); + t.glcd_align_start = configfile.getInt32("glcd_align_start", 0); + t.glcd_align_end = configfile.getInt32("glcd_align_end", 0); + t.glcd_align_time = configfile.getInt32("glcd_align_time", 0); + t.glcd_percent_channel = configfile.getInt32("glcd_percent_channel", 0); + t.glcd_channel_x_position = configfile.getInt32("glcd_channel_x_position", 0); + t.glcd_channel_y_position = configfile.getInt32("glcd_channel_y_position", 0); + t.glcd_percent_epg = configfile.getInt32("glcd_percent_epg", 0); + t.glcd_epg_x_position = configfile.getInt32("glcd_epg_x_position", 0); + t.glcd_epg_y_position = configfile.getInt32("glcd_epg_y_position", 0); + t.glcd_percent_duration = configfile.getInt32("glcd_percent_duration", 0); + t.glcd_duration_x_position = configfile.getInt32("glcd_duration_x_position", 0); + t.glcd_duration_y_position = configfile.getInt32("glcd_duration_y_position", 0); + t.glcd_percent_start = configfile.getInt32("glcd_percent_start", 0); + t.glcd_start_x_position = configfile.getInt32("glcd_start_x_position", 0); + t.glcd_start_y_position = configfile.getInt32("glcd_start_y_position", 0); + t.glcd_percent_end = configfile.getInt32("glcd_percent_end", 0); + t.glcd_end_x_position = configfile.getInt32("glcd_end_x_position", 0); + t.glcd_end_y_position = configfile.getInt32("glcd_end_y_position", 0); + t.glcd_percent_time = configfile.getInt32("glcd_percent_time", 0); + t.glcd_time_x_position = configfile.getInt32("glcd_time_x_position", 0); + t.glcd_time_y_position = configfile.getInt32("glcd_time_y_position", 0); + t.glcd_percent_bar = configfile.getInt32("glcd_percent_bar", 0); + t.glcd_bar_x_position = configfile.getInt32("glcd_bar_x_position", 0); + t.glcd_bar_y_position = configfile.getInt32("glcd_bar_y_position", 0); + t.glcd_bar_width = configfile.getInt32("glcd_bar_width", 0); + t.glcd_percent_logo = configfile.getInt32("glcd_percent_logo", 0); + t.glcd_logo_x_position = configfile.getInt32("glcd_logo_x_position", 0); + t.glcd_logo_y_position = configfile.getInt32("glcd_logo_y_position", 0); + t.glcd_percent_smalltext = configfile.getInt32("glcd_percent_smalltext", 0); + t.glcd_smalltext_y_position = configfile.getInt32("glcd_smalltext_y_position", 0); + t.glcd_rec_icon_x_position = configfile.getInt32("glcd_rec_icon_x_position", 0); + t.glcd_mute_icon_x_position = configfile.getInt32("glcd_mute_icon_x_position", 0); + t.glcd_ts_icon_x_position = configfile.getInt32("glcd_ts_icon_x_position", 0); + t.glcd_timer_icon_x_position = configfile.getInt32("glcd_timer_icon_x_position", 0); + t.glcd_ecm_icon_x_position = configfile.getInt32("glcd_ecm_icon_x_position", 0); + t.glcd_dd_icon_x_position = configfile.getInt32("glcd_dd_icon_x_position", 0); + t.glcd_txt_icon_x_position = configfile.getInt32("glcd_txt_icon_x_position", 0); + t.glcd_cam_icon_x_position = configfile.getInt32("glcd_cam_icon_x_position", 0); + t.glcd_digital_clock_y_position = configfile.getInt32("glcd_digital_clock_y_position", 0); + t.glcd_size_simple_clock = configfile.getInt32("glcd_size_simple_clock", 0); + t.glcd_simple_clock_y_position = configfile.getInt32("glcd_simple_clock_y_position", 0); + t.glcd_weather_x_position_current = configfile.getInt32("glcd_weather_x_position_current", 0); + t.glcd_weather_x_position_next = configfile.getInt32("glcd_weather_x_position_next", 0); + t.glcd_weather_y_position = configfile.getInt32("glcd_weather_y_position", 0); + t.glcd_weather_x_position_current_standby = configfile.getInt32("glcd_weather_x_position_current_standby", 0); + t.glcd_weather_x_position_next_standby = configfile.getInt32("glcd_weather_x_position_next_standby", 0); + t.glcd_weather_y_position_standby = configfile.getInt32("glcd_weather_y_position_standby", 0); + t.glcd_position_settings = configfile.getInt32("glcd_position_settings", 0); + + if (g_settings.glcd_theme_name.empty()) + applyDefaultTheme(); +} + +void CGLCDThemes::move_userDir() +{ + if (access(USERDIR, F_OK) == 0) + { + if (!CFileHelpers::createDir(THEMESDIR_VAR)) + { + printf("[neutrino glcd theme] error creating %s\n", THEMESDIR_VAR); + return; + } + struct dirent **themelist; + int n = scandir(USERDIR, &themelist, 0, alphasort); + if (n < 0) + { + perror("loading glcd themes: scandir"); + return; + } + else + { + for (int count = 0; count < n; count++) + { + const char *file = themelist[count]->d_name; + if (strcmp(file, ".") == 0 || strcmp(file, "..") == 0) + continue; + const char *dest = ((std::string)USERDIR + "/" + file).c_str(); + const char *target = ((std::string)THEMESDIR_VAR + "/" + file).c_str(); + printf("[neutrino gcdl theme] moving %s to %s\n", dest, target); + rename(dest, target); + free(themelist[count]); + } + free(themelist); + } + printf("[neutrino gcld theme] removing %s\n", USERDIR); + remove(USERDIR); + } +} + +void CGLCDThemes::markSelectedTheme(CMenuWidget *w) +{ + for (int i = 0; i < w->getItemsCount(); i++){ + w->getItem(i)->setInfoIconRight(NULL); + if (g_settings.glcd_theme_name == w->getItem(i)->getName()) + w->getItem(i)->setInfoIconRight(NEUTRINO_ICON_MARKER_DIALOG_OK); + } +} diff --git a/src/gui/glcdthemes.h b/src/gui/glcdthemes.h new file mode 100644 index 000000000..f1421b7ff --- /dev/null +++ b/src/gui/glcdthemes.h @@ -0,0 +1,66 @@ +/* + $port: themes.h,v 1.6 2010/06/01 19:58:38 tuxbox-cvs Exp $ + + Neutrino-GUI - DBoxII-Project + + License: GPL + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + Copyright (C) 2007, 2008, 2009 (flasher) Frank Liebelt +*/ + +#ifndef __cglcdthemes__ +#define __cglcdthemes__ +#include +#include +#include +#include +#include + +#define MIGRATE_THEME_OLED_NAME "Unknown-Migrated-Oled-Theme" + +class CGLCDThemes : public CMenuTarget, CColorSetupNotifier, public sigc::trackable +{ + private: + CConfigFile themefile; + + int width; + SNeutrinoGlcdTheme oldTheme; + std::string oldTheme_name; + + bool hasThemeChanged; + + int Show(); + void readFile(const char *themename); + void saveFile(const char *themename); + void initThemesMenu(CMenuWidget &); + void rememberOldTheme(bool remember); + void move_userDir(); + bool applyDefaultTheme(); + ///signal after select theme is completed + sigc::signal OnAfterSelectTheme; + void markSelectedTheme(CMenuWidget *w); + + public: + CGLCDThemes(); + static CGLCDThemes* getInstance(); + void setupDefaultColors(); + int exec(CMenuTarget* parent, const std::string & actionKey); + void setTheme(CConfigFile &configfile); + void getTheme(CConfigFile &configfile); +}; + +#endif diff --git a/src/gui/infoviewer.cpp b/src/gui/infoviewer.cpp index 7450feae6..820eb9641 100644 --- a/src/gui/infoviewer.cpp +++ b/src/gui/infoviewer.cpp @@ -1546,12 +1546,20 @@ int CInfoViewer::handleMsg (const neutrino_msg_t msg, neutrino_msg_data_t data) showLcdPercentOver (); eventname = info_CurrentNext.current_name; CVFD::getInstance()->setEPGTitle(eventname); +#ifdef ENABLE_GRAPHLCD + if (g_settings.glcd_enable) + cGLCD::lockChannel("", eventname, 0); +#endif return messages_return::handled; } else if (msg == NeutrinoMessages::EVT_ZAP_SUB_FAILED) { //chanready = 1; showSNR (); // show failure..! CVFD::getInstance ()->showServicename ("(" + g_RemoteControl->getCurrentChannelName () + ')', g_RemoteControl->getCurrentChannelNumber()); +#ifdef ENABLE_GRAPHLCD + if (g_settings.glcd_enable) + cGLCD::lockChannel("(" + g_RemoteControl->getCurrentChannelName () + ')', "", 0); +#endif printf ("zap failed!\n"); showFailure (); CVFD::getInstance ()->showPercentOver (255); @@ -1562,6 +1570,10 @@ int CInfoViewer::handleMsg (const neutrino_msg_t msg, neutrino_msg_data_t data) if ((*(t_channel_id *) data) == current_channel_id) { // show failure..! CVFD::getInstance ()->showServicename ("(" + g_RemoteControl->getCurrentChannelName () + ')', g_RemoteControl->getCurrentChannelNumber()); +#ifdef ENABLE_GRAPHLCD + if (g_settings.glcd_enable) + cGLCD::lockChannel("(" + g_RemoteControl->getCurrentChannelName () + ')', "", 0); +#endif printf ("zap failed!\n"); showFailure (); CVFD::getInstance ()->showPercentOver (255); diff --git a/src/gui/infoviewer_bb.cpp b/src/gui/infoviewer_bb.cpp index 9f6522ee1..67c6ee4bc 100644 --- a/src/gui/infoviewer_bb.cpp +++ b/src/gui/infoviewer_bb.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -512,6 +513,12 @@ void CInfoViewerBB::showIcon_SubT() have_sub = true; showBBIcons(CInfoViewerBB::ICON_SUBT, (have_sub) ? NEUTRINO_ICON_SUBT : NEUTRINO_ICON_SUBT_GREY); +#ifdef ENABLE_GRAPHLCD + if (cc && cc->getSubtitleCount()) + cGLCD::lockIcon(cGLCD::SUB); + else + cGLCD::unlockIcon(cGLCD::SUB); +#endif } void CInfoViewerBB::showIcon_VTXT() @@ -519,6 +526,12 @@ void CInfoViewerBB::showIcon_VTXT() if (!is_visible) return; showBBIcons(CInfoViewerBB::ICON_VTXT, (g_RemoteControl->current_PIDs.PIDs.vtxtpid != 0) ? NEUTRINO_ICON_VTXT : NEUTRINO_ICON_VTXT_GREY); +#ifdef ENABLE_GRAPHLCD + if (g_RemoteControl->current_PIDs.PIDs.vtxtpid) + cGLCD::lockIcon(cGLCD::TXT); + else + cGLCD::unlockIcon(cGLCD::TXT); +#endif } void CInfoViewerBB::showIcon_DD() @@ -529,10 +542,17 @@ void CInfoViewerBB::showIcon_DD() if ((g_RemoteControl->current_PIDs.PIDs.selected_apid < g_RemoteControl->current_PIDs.APIDs.size()) && (g_RemoteControl->current_PIDs.APIDs[g_RemoteControl->current_PIDs.PIDs.selected_apid].is_ac3)) dd_icon = NEUTRINO_ICON_DD; - else + else dd_icon = g_RemoteControl->has_ac3 ? NEUTRINO_ICON_DD_AVAIL : NEUTRINO_ICON_DD_GREY; showBBIcons(CInfoViewerBB::ICON_DD, dd_icon); +#ifdef ENABLE_GRAPHLCD + if ((g_RemoteControl->current_PIDs.PIDs.selected_apid < g_RemoteControl->current_PIDs.APIDs.size()) && + (g_RemoteControl->current_PIDs.APIDs[g_RemoteControl->current_PIDs.PIDs.selected_apid].is_ac3)) + cGLCD::lockIcon(cGLCD::DD); + else + cGLCD::unlockIcon(cGLCD::DD); +#endif } void CInfoViewerBB::showIcon_RadioText(bool rt_available) diff --git a/src/gui/miscsettings_menu.cpp b/src/gui/miscsettings_menu.cpp index 03fc07a10..f666dbeaa 100644 --- a/src/gui/miscsettings_menu.cpp +++ b/src/gui/miscsettings_menu.cpp @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include #include #include @@ -177,6 +179,13 @@ int CMiscMenue::exec(CMenuTarget* parent, const std::string &actionKey) return showMiscSettingsMenu(); } +#define WEATHER_COUNTRY_OPTION_COUNT 2 +const CMenuOptionChooser::keyval WEATHER_COUNTRY_OPTIONS[WEATHER_COUNTRY_OPTION_COUNT] = +{ + { 0, LOCALE_WEATHER_COUNTRY_DEUTSCHLAND }, + { 1, LOCALE_WEATHER_COUNTRY_NORWAY } +}; + #if 0 //not used #define MISCSETTINGS_FB_DESTINATION_OPTION_COUNT 3 const CMenuOptionChooser::keyval MISCSETTINGS_FB_DESTINATION_OPTIONS[MISCSETTINGS_FB_DESTINATION_OPTION_COUNT] = @@ -618,6 +627,9 @@ int CMiscMenue::showMiscSettingsMenuOnlineServices() mf_we->setHint(NEUTRINO_ICON_HINT_SETTINGS, LOCALE_MENU_HINT_WEATHER_API_KEY); ms_oservices->addItem(mf_we); #endif + CMenuOptionChooser *mf_wc = new CMenuOptionChooser(LOCALE_WEATHER_COUNTRY, &g_settings.weather_country, WEATHER_COUNTRY_OPTIONS, WEATHER_COUNTRY_OPTION_COUNT, true); + mf_wc->setHint(NEUTRINO_ICON_HINT_SETTINGS, LOCALE_MENU_HINT_WEATHER_COUNTRY); + ms_oservices->addItem(mf_wc); CMenuForwarder *mf_wl = new CMenuForwarder(LOCALE_WEATHER_LOCATION, g_settings.weather_enabled, g_settings.weather_city, this, "select_location"); mf_wl->setHint(NEUTRINO_ICON_HINT_SETTINGS, LOCALE_MENU_HINT_WEATHER_LOCATION); @@ -719,7 +731,17 @@ int CMiscMenue::showMiscSettingsSelectWeatherLocation() int select = 0; int res = 0; - if (WEATHER_LOCATION_OPTION_COUNT > 1) + int location_option_count = 0; + const struct weather_loc *location = NULL; + if (g_settings.weather_country == DEUTSCHLAND) { + location_option_count = WEATHER_DEUTSCHLAND_LOCATION_OPTION_COUNT; + location = WEATHER_DEUTSCHLAND_LOCATION_OPTIONS; + } else if (g_settings.weather_country == NORWAY) { + location_option_count = WEATHER_NORWAY_LOCATION_OPTION_COUNT; + location = WEATHER_NORWAY_LOCATION_OPTIONS; + } + + if (location_option_count > 1) { CMenuWidget *m = new CMenuWidget(LOCALE_WEATHER_LOCATION, NEUTRINO_ICON_LANGUAGE); CMenuSelectorTarget * selector = new CMenuSelectorTarget(&select); @@ -727,10 +749,10 @@ int CMiscMenue::showMiscSettingsSelectWeatherLocation() m->addItem(GenericMenuSeparator); CMenuForwarder* mf; - for (size_t i = 0; i < WEATHER_LOCATION_OPTION_COUNT; i++) + for (int i = 0; i < location_option_count; i++) { - mf = new CMenuForwarder(WEATHER_LOCATION_OPTIONS[i].key, true, NULL, selector, to_string(i).c_str()); - mf->setHint(NEUTRINO_ICON_HINT_SETTINGS, WEATHER_LOCATION_OPTIONS[i].value.c_str()); + mf = new CMenuForwarder(location[i].key, true, NULL, selector, to_string(i).c_str()); + mf->setHint(NEUTRINO_ICON_HINT_SETTINGS, location[i].value.c_str()); m->addItem(mf); } @@ -742,8 +764,8 @@ int CMiscMenue::showMiscSettingsSelectWeatherLocation() delete selector; } - g_settings.weather_location = WEATHER_LOCATION_OPTIONS[select].value; - g_settings.weather_city = std::string(WEATHER_LOCATION_OPTIONS[select].key); + g_settings.weather_location = location[select].value; + g_settings.weather_city = std::string(location[select].key); CWeather::getInstance()->setCoords(g_settings.weather_location, g_settings.weather_city); return res; } diff --git a/src/gui/miscsettings_menu.h b/src/gui/miscsettings_menu.h index c8d0e98a4..376d136d8 100644 --- a/src/gui/miscsettings_menu.h +++ b/src/gui/miscsettings_menu.h @@ -38,6 +38,10 @@ class CMiscMenue : public CMenuTarget, CChangeObserver { private: + enum { + DEUTSCHLAND = 0, + NORWAY = 1, + }; CFanControlNotifier *fanNotifier; CSectionsdConfigNotifier* sectionsdConfigNotifier; //COnOffNotifier* miscNotifier; diff --git a/src/gui/movieplayer.cpp b/src/gui/movieplayer.cpp index ddc86b5e6..6fb2d0ca8 100644 --- a/src/gui/movieplayer.cpp +++ b/src/gui/movieplayer.cpp @@ -84,10 +84,6 @@ //NI InfoIcons #include -#ifdef ENABLE_GRAPHLCD -bool glcd_play = false; -#endif - #if HAVE_COOL_HARDWARE || HAVE_ARM_HARDWARE || HAVE_MIPS_HARDWARE #define LCD_MODE CVFD::MODE_MENU_UTF8 #else @@ -391,6 +387,21 @@ int CMoviePlayerGui::exec(CMenuTarget * parent, const std::string & actionKey) } } +#ifdef ENABLE_GRAPHLCD + if (!bgThread) { + cGLCD::MirrorOSD(false); + + channel = g_Locale->getText(LOCALE_MOVIEPLAYER_HEAD); + + epg = g_Locale->getText(LOCALE_MPKEY_STOP); + cGLCD::ShowLcdIcon(false); + cGLCD::lockChannel(channel, epg, 0); + cGLCD::lockDuration("00/00"); + cGLCD::lockStart("00:00"); + cGLCD::lockEnd("00:00"); + } +#endif + exec_controlscript(MOVIEPLAYER_START_SCRIPT); Cleanup(); @@ -488,11 +499,39 @@ int CMoviePlayerGui::exec(CMenuTarget * parent, const std::string & actionKey) timeshift = TSHIFT_MODE_OFF; return menu_return::RETURN_EXIT_ALL; } + +#ifdef ENABLE_GRAPHLCD + if (!isHTTP || !isUPNP || !bgThread) { + cGLCD::MirrorOSD(g_settings.glcd_mirror_osd); + cGLCD::ShowLcdIcon(false); + cGLCD::unlockChannel(); + cGLCD::unlockDuration(); + cGLCD::unlockStart(); + cGLCD::unlockEnd(); + } +#endif + return menu_ret; } void CMoviePlayerGui::updateLcd(bool display_playtime) { +#ifdef ENABLE_GRAPHLCD + if (!bgThread) { + if (CMoviePlayerGui::getInstance().p_movie_info) + { + if (!CMoviePlayerGui::getInstance().p_movie_info->channelName.empty()) + channel = CMoviePlayerGui::getInstance().p_movie_info->channelName; + if (!CMoviePlayerGui::getInstance().p_movie_info->epgTitle.empty()) + epg = CMoviePlayerGui::getInstance().p_movie_info->epgTitle; + } else if (!CMoviePlayerGui::getInstance().GetFile().empty()) { + epg = CMoviePlayerGui::getInstance().GetFile(); + } + + if (channel.empty()) + channel = g_Locale->getText(LOCALE_MOVIEPLAYER_HEAD); + } +#endif char tmp[20]; std::string lcd; std::string name; @@ -515,7 +554,32 @@ void CMoviePlayerGui::updateLcd(bool display_playtime) switch (playstate) { + case CMoviePlayerGui::STOPPED: +#ifdef ENABLE_GRAPHLCD + if (!bgThread) { + channel = g_Locale->getText(LOCALE_MOVIEPLAYER_HEAD); + + epg = g_Locale->getText(LOCALE_MPKEY_STOP); + + cGLCD::ShowLcdIcon(false); + cGLCD::lockChannel(channel, epg, 0); + cGLCD::lockDuration("00/00"); + cGLCD::lockStart("00:00"); + cGLCD::lockEnd("00:00"); + } +#endif + break; case CMoviePlayerGui::PAUSE: +#ifdef ENABLE_GRAPHLCD + if (!bgThread) { + channel = ""; + cGLCD::lockChannel(channel, epg, glcd_position); + cGLCD::lockDuration(glcd_duration); + cGLCD::lockStart(start); + cGLCD::lockEnd(end); + cGLCD::ShowLcdIcon(true); + } +#endif if (speed < 0) { sprintf(tmp, "%dx<| ", abs(speed)); @@ -530,14 +594,44 @@ void CMoviePlayerGui::updateLcd(bool display_playtime) lcd = "|| "; break; case CMoviePlayerGui::REW: +#ifdef ENABLE_GRAPHLCD + if (!bgThread) { + channel = ""; + cGLCD::lockChannel(channel, epg, glcd_position); + cGLCD::lockDuration(glcd_duration); + cGLCD::lockStart(start); + cGLCD::lockEnd(end); + cGLCD::ShowLcdIcon(true); + } +#endif sprintf(tmp, "%dx<< ", abs(speed)); lcd = tmp; break; case CMoviePlayerGui::FF: +#ifdef ENABLE_GRAPHLCD + if (!bgThread) { + channel = ""; + cGLCD::lockChannel(channel, epg, glcd_position); + cGLCD::lockDuration(glcd_duration); + cGLCD::lockStart(start); + cGLCD::lockEnd(end); + cGLCD::ShowLcdIcon(true); + } +#endif sprintf(tmp, "%dx>> ", abs(speed)); lcd = tmp; break; case CMoviePlayerGui::PLAY: +#ifdef ENABLE_GRAPHLCD + if (!bgThread) { + channel = ""; + cGLCD::lockChannel(channel, epg, glcd_position); + cGLCD::lockDuration(glcd_duration); + cGLCD::lockStart(start); + cGLCD::lockEnd(end); + cGLCD::ShowLcdIcon(true); + } +#endif lcd = "> "; break; default: @@ -1292,6 +1386,19 @@ void CMoviePlayerGui::stopPlayBack(void) webtv_started = false; if(playback) playback->RequestAbort(); +#ifdef ENABLE_GRAPHLCD + if (!bgThread) { + channel = g_Locale->getText(LOCALE_MOVIEPLAYER_HEAD); + + epg = g_Locale->getText(LOCALE_MPKEY_STOP); + + cGLCD::ShowLcdIcon(false); + cGLCD::lockChannel(channel, epg, 0); + cGLCD::lockDuration("00/00"); + cGLCD::lockStart("00:00"); + cGLCD::lockEnd("00:00"); + } +#endif mutex.unlock(); cond.broadcast(); pthread_join(bgThread, NULL); @@ -1375,13 +1482,7 @@ bool CMoviePlayerGui::PlayFileStart(void) } #ifdef ENABLE_GRAPHLCD - nGLCD::MirrorOSD(false); - if (p_movie_info) - nGLCD::lockChannel(p_movie_info->channelName, p_movie_info->epgTitle); - else { - glcd_play = true; - nGLCD::lockChannel(g_Locale->getText(LOCALE_MOVIEPLAYER_HEAD), file_name.c_str(), file_prozent); - } + cGLCD::MirrorOSD(false); #endif file_prozent = 0; @@ -1578,14 +1679,6 @@ void CMoviePlayerGui::PlayFileLoop(void) while (playstate >= CMoviePlayerGui::PLAY) { -#ifdef ENABLE_GRAPHLCD - if (p_movie_info) - nGLCD::lockChannel(p_movie_info->channelName, p_movie_info->epgTitle, duration ? (100 * position / duration) : 0); - else { - glcd_play = true; - nGLCD::lockChannel(g_Locale->getText(LOCALE_MOVIEPLAYER_HEAD), file_name.c_str(), file_prozent); - } -#endif if (update_lcd || g_settings.movieplayer_display_playtime) { update_lcd = false; updateLcd(g_settings.movieplayer_display_playtime); @@ -1639,6 +1732,32 @@ void CMoviePlayerGui::PlayFileLoop(void) if (duration > 100) file_prozent = (unsigned char) (position / (duration / 100)); +#ifdef ENABLE_GRAPHLCD + if (!bgThread) { + int pos = position / (60 * 1000); + int dur = duration / (60 * 1000); + + glcd_duration = to_string(position / (60 * 1000)) + "/" + to_string(duration / (60 * 1000)); + //glcd_duration = to_string(pos/10) + to_string(pos%10) + "/" + to_string(dur/10) + to_string(dur%10); + + time_t sTime = time(NULL); + sTime -= (position / 1000); + tm_struct = localtime(&sTime); + start = to_string(tm_struct->tm_hour/10) + to_string(tm_struct->tm_hour%10) + ":" + to_string(tm_struct->tm_min/10) + to_string(tm_struct->tm_min%10); + + time_t eTime = time(NULL); + eTime += (duration / 1000) - (position / 1000); + tm_struct = localtime(&eTime); + end = to_string(tm_struct->tm_hour/10) + to_string(tm_struct->tm_hour%10) + ":" + to_string(tm_struct->tm_min/10) + to_string(tm_struct->tm_min%10); + + //glcd_position = duration ? 100 * (position / duration) : 0; + glcd_position = file_prozent; + cGLCD::lockChannel(channel, epg, glcd_position); + cGLCD::lockDuration(glcd_duration); + cGLCD::lockStart(start); + cGLCD::lockEnd(end); + } +#endif CVFD::getInstance()->showPercentOver(file_prozent); playback->GetSpeed(speed); @@ -2098,9 +2217,16 @@ void CMoviePlayerGui::PlayFileEnd(bool restore) playback->SetSpeed(1); playback->Close(); #ifdef ENABLE_GRAPHLCD - if (p_movie_info || glcd_play == true) { - glcd_play = false; - nGLCD::unlockChannel(); + if (!bgThread) { + channel = g_Locale->getText(LOCALE_MOVIEPLAYER_HEAD); + + epg = g_Locale->getText(LOCALE_MPKEY_STOP); + + cGLCD::ShowLcdIcon(false); + cGLCD::lockChannel(channel, epg, 0); + cGLCD::lockDuration("00/00"); + cGLCD::lockStart("00:00"); + cGLCD::lockEnd("00:00"); } #endif if (iso_file) { @@ -2252,8 +2378,10 @@ void CMoviePlayerGui::callInfoViewer(bool init_vzap_it) if (!movie_info.channelName.empty() || !movie_info.epgTitle.empty()) p_movie_info = &movie_info; #ifdef ENABLE_GRAPHLCD + if (!bgThread) { if (p_movie_info) - nGLCD::lockChannel(p_movie_info->channelName, p_movie_info->epgTitle); + cGLCD::lockChannel(p_movie_info->channelName, p_movie_info->epgTitle); + } #endif } diff --git a/src/gui/movieplayer.h b/src/gui/movieplayer.h index a9096b35b..bee808f96 100644 --- a/src/gui/movieplayer.h +++ b/src/gui/movieplayer.h @@ -115,6 +115,16 @@ class CMoviePlayerGui : public CMenuTarget int m_LastMode; int m_ThisMode; +#ifdef ENABLE_GRAPHLCD + struct tm *tm_struct; + int glcd_position; + std::string channel; + std::string epg; + std::string glcd_duration; + std::string start; + std::string end; +#endif + std::string cookie_header; std::string info_1, info_2; std::string currentaudioname; diff --git a/src/gui/pictureviewer.cpp b/src/gui/pictureviewer.cpp index eda9868d6..e5537e5b9 100644 --- a/src/gui/pictureviewer.cpp +++ b/src/gui/pictureviewer.cpp @@ -166,6 +166,13 @@ int CPictureViewerGui::exec(CMenuTarget* parent, const std::string & actionKey) selected = 0; +#ifdef ENABLE_GRAPHLCD + cGLCD::MirrorOSD(false); + channel = g_Locale->getText(LOCALE_PICTUREVIEWER_HEAD); + epg = ""; + cGLCD::lockChannel(channel, epg, 0); +#endif + width = frameBuffer->getWindowWidth(); height = frameBuffer->getWindowHeight(); @@ -243,6 +250,11 @@ int CPictureViewerGui::exec(CMenuTarget* parent, const std::string & actionKey) if (m_LastMode == NeutrinoModes::mode_ts) videoDecoder->setBlank(false); +#ifdef ENABLE_GRAPHLCD + cGLCD::MirrorOSD(g_settings.glcd_mirror_osd); + cGLCD::unlockChannel(); +#endif + // always exit all return menu_return::RETURN_REPAINT; } @@ -588,6 +600,10 @@ int CPictureViewerGui::show() CNFSSmallMenu nfsMenu; nfsMenu.exec(this, ""); update=true; +#ifdef ENABLE_GRAPHLCD + epg = ""; + cGLCD::lockChannel(channel, epg, 0); +#endif CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, g_Locale->getText(LOCALE_PICTUREVIEWER_HEAD)); } } @@ -802,6 +818,10 @@ void CPictureViewerGui::view(unsigned int index, bool unscaled) m_unscaled = unscaled; selected=index; +#ifdef ENABLE_GRAPHLCD + epg = playlist[index].Name.c_str(); + cGLCD::lockChannel(channel, epg, 0); +#endif CVFD::getInstance()->showMenuText(0, playlist[index].Name.c_str()); char timestring[19]; strftime(timestring, 18, "%d-%m-%Y %H:%M", gmtime(&playlist[index].Date)); @@ -852,6 +872,11 @@ void CPictureViewerGui::thrView() void CPictureViewerGui::endView() { +#ifdef ENABLE_GRAPHLCD + epg = ""; + cGLCD::lockChannel(channel, epg, 0); +#endif + if (m_state != MENU) m_state=MENU; @@ -864,6 +889,10 @@ void CPictureViewerGui::endView() void CPictureViewerGui::deletePicFile(unsigned int index, bool mode) { +#ifdef ENABLE_GRAPHLCD + epg = playlist[index].Name.c_str(); + cGLCD::lockChannel(channel, epg, 0); +#endif CVFD::getInstance()->showMenuText(0, playlist[index].Name.c_str()); if (ShowMsg(LOCALE_FILEBROWSER_DELETE, playlist[index].Filename, CMsgBox::mbrNo, CMsgBox::mbYes|CMsgBox::mbNo)==CMsgBox::mbrYes) { diff --git a/src/gui/pictureviewer.h b/src/gui/pictureviewer.h index 70b38fd16..be4793102 100644 --- a/src/gui/pictureviewer.h +++ b/src/gui/pictureviewer.h @@ -86,6 +86,11 @@ class CPictureViewerGui : public CMenuTarget CViewList playlist; std::string Path; +#ifdef ENABLE_GRAPHLCD + std::string channel; + std::string epg; +#endif + int width; int height; int x; diff --git a/src/gui/scan.cpp b/src/gui/scan.cpp index af8e95f9d..62eb2728f 100644 --- a/src/gui/scan.cpp +++ b/src/gui/scan.cpp @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -385,6 +386,9 @@ int CScanTs::exec(CMenuTarget* /*parent*/, const std::string & actionKey) CNeutrinoApp::getInstance()->channelList->zapTo_ChannelID(CZapit::getInstance()->GetCurrentChannelID(), true); /* force re-zap */ CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); +#ifdef ENABLE_GRAPHLCD + cGLCD::unlockChannel(); +#endif return menu_return::RETURN_REPAINT; } @@ -409,6 +413,11 @@ neutrino_msg_t CScanTs::handleMsg(neutrino_msg_t msg, neutrino_msg_data_t data) total = data; snprintf(str, sizeof(buffer), "scan: %d/%d", done, total); CVFD::getInstance()->showMenuText(0, str, -1, true); +#ifdef ENABLE_GRAPHLCD + if (g_settings.glcd_enable) + cGLCD::lockChannel(g_Locale->getText(LOCALE_SCANTS_HEAD), str, 0); + //cGLCD::lockChannel(g_Locale->getText(LOCALE_BOUQUETLIST_HEAD), chan->getName().c_str(), 0); +#endif break; case NeutrinoMessages::EVT_SCAN_REPORT_NUM_SCANNED_TRANSPONDERS: @@ -418,6 +427,10 @@ neutrino_msg_t CScanTs::handleMsg(neutrino_msg_t msg, neutrino_msg_data_t data) paintLine(xpos2, ypos_transponder, (ypos_transponder > ypos_radar + 66) ? w : w_to_radar, buffer); snprintf(str, sizeof(buffer), "scan %d/%d", done, total); CVFD::getInstance()->showMenuText(0, str, -1, true); +#ifdef ENABLE_GRAPHLCD + if (g_settings.glcd_enable) + cGLCD::lockChannel(g_Locale->getText(LOCALE_SCANTS_HEAD), str, 0); +#endif break; case NeutrinoMessages::EVT_SCAN_REPORT_FREQUENCYP: diff --git a/src/gui/upnpbrowser.cpp b/src/gui/upnpbrowser.cpp index 2f3030d31..ab07ec85a 100644 --- a/src/gui/upnpbrowser.cpp +++ b/src/gui/upnpbrowser.cpp @@ -187,6 +187,11 @@ int CUpnpBrowserGui::exec(CMenuTarget* parent, const std::string & /*actionKey*/ CNeutrinoApp::getInstance()->stopPlayBack(true); m_frameBuffer->showFrame("mp3.jpg"); +#ifdef ENABLE_GRAPHLCD + cGLCD::MirrorOSD(false); + cGLCD::lockChannel(g_Locale->getText(LOCALE_UPNPBROWSER_HEAD), "", 0); +#endif + // tell neutrino we're in upnp mode CNeutrinoApp::getInstance()->handleMsg(NeutrinoMessages::CHANGEMODE , NeutrinoModes::mode_upnp); @@ -210,6 +215,11 @@ int CUpnpBrowserGui::exec(CMenuTarget* parent, const std::string & /*actionKey*/ CNeutrinoApp::getInstance()->handleMsg(NeutrinoMessages::CHANGEMODE , m_LastMode); g_RCInput->postMsg(NeutrinoMessages::SHOW_INFOBAR, 0); +#ifdef ENABLE_GRAPHLCD + cGLCD::MirrorOSD(g_settings.glcd_mirror_osd); + cGLCD::unlockChannel(); +#endif + return menu_return::RETURN_REPAINT; } diff --git a/src/gui/vfd_setup.cpp b/src/gui/vfd_setup.cpp index 2a8a348c6..d8d35e9a4 100644 --- a/src/gui/vfd_setup.cpp +++ b/src/gui/vfd_setup.cpp @@ -195,8 +195,6 @@ int CVfdSetup::showSetup() #ifdef ENABLE_GRAPHLCD GLCD_Menu glcdMenu; - - vfds->addItem(GenericMenuSeparatorLine); vfds->addItem(new CMenuForwarder(LOCALE_GLCD_HEAD, true, NULL, &glcdMenu, NULL, CRCInput::RC_blue)); #endif diff --git a/src/gui/weather.cpp b/src/gui/weather.cpp index 0cba28a36..a62042ea8 100644 --- a/src/gui/weather.cpp +++ b/src/gui/weather.cpp @@ -139,11 +139,15 @@ bool CWeather::GetWeatherDetails() current.humidity = DataValues["currently"].get("humidity", "").asFloat(); current.windSpeed = DataValues["currently"].get("windSpeed", "").asFloat(); current.windBearing = DataValues["currently"].get("windBearing", "").asDouble(); - current.icon = DataValues["currently"].get("icon", "").asString(); + current.icon = current.icon_only_name = DataValues["currently"].get("icon", "").asString(); if (current.icon.empty()) current.icon = "unknown.png"; else current.icon = current.icon + ".png"; + + if (current.icon_only_name.empty()) + current.icon_only_name = "unknown"; + printf("[CWeather]: temp in %s (%s): %.1f - %s\n", city.c_str(), timezone.c_str(), current.temperature, current.icon.c_str()); forecast_data daily_data; @@ -152,11 +156,15 @@ bool CWeather::GetWeatherDetails() { daily_data.timestamp = elements[i].get("time", 0).asDouble(); daily_data.weekday = (int)(localtime(&daily_data.timestamp)->tm_wday); - daily_data.icon = elements[i].get("icon", "").asString(); + daily_data.icon = daily_data.icon_only_name = elements[i].get("icon", "").asString(); if (daily_data.icon.empty()) daily_data.icon = "unknown.png"; else daily_data.icon = daily_data.icon + ".png"; + + if (daily_data.icon_only_name.empty()) + daily_data.icon_only_name = "unknown"; + daily_data.temperatureMin = elements[i].get("temperatureMin", "").asFloat(); daily_data.temperatureMax = elements[i].get("temperatureMax", "").asFloat(); daily_data.sunriseTime = elements[i].get("sunriseTime", 0).asDouble(); diff --git a/src/gui/weather.h b/src/gui/weather.h index f1162ac8f..0f9438364 100644 --- a/src/gui/weather.h +++ b/src/gui/weather.h @@ -39,6 +39,7 @@ struct current_data { time_t timestamp; std::string icon; + std::string icon_only_name; float temperature; float humidity; float pressure; @@ -48,6 +49,7 @@ struct current_data current_data(): timestamp(0), icon("unknown.png"), + icon_only_name("unknown"), temperature(0), humidity(0), pressure(0), @@ -61,6 +63,7 @@ typedef struct time_t timestamp; int weekday; // 0=Sunday, 1=Monday, ... std::string icon; + std::string icon_only_name; float temperatureMin; float temperatureMax; time_t sunriseTime; @@ -130,6 +133,10 @@ class CWeather { return ICONSDIR"/weather/" + current.icon; }; + std::string getCurrentIconOnlyName() + { + return current.icon_only_name; + }; // forecast conditions int getForecastSize() @@ -172,6 +179,12 @@ class CWeather i = (int)v_forecast.size(); return ICONSDIR"/weather/" + v_forecast[i].icon; }; + std::string getForecastIconOnlyNane(int i = 0) + { + if (i > (int)v_forecast.size()) + i = (int)v_forecast.size(); + return v_forecast[i].icon_only_name; + }; void show(int x = 50, int y = 50); void hide(); diff --git a/src/gui/weather_deutschland_locations.h b/src/gui/weather_deutschland_locations.h new file mode 100644 index 000000000..e771e2ca9 --- /dev/null +++ b/src/gui/weather_deutschland_locations.h @@ -0,0 +1,319 @@ +/* + Copyright (C) 2017,2018,2019 TangoCash + + “Powered by Dark Sky” https://darksky.net/poweredby/ + + License: GPLv2 + + 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; + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _WEATHER_DEUTSCHLAND_LOCATION_H_ +#define _WEATHER_DEUTSCHLAND_LOCATION_H_ + +#include "weather_locations.h" + +// locations and coords taken from tuxwetter plugin +const weather_loc WEATHER_DEUTSCHLAND_LOCATION_OPTIONS[] = +{ + { "Aachen", "50.77,6.13" }, + { "Ahaus", "52.07,7.00" }, + { "Ahrensburg", "53.06,10.25" }, + { "Allendorf", "51.28,7.95" }, + { "Alsenz", "49.72,7.82" }, + { "Altenbruch", "53.82,8.77" }, + { "Amberg", "49.44,11.86" }, + { "Ansbach", "49.30,10.58" }, + { "Aschaffenburg", "49.97,9.15" }, + { "Augsburg", "48.37,10.88" }, + { "Aurich", "53.47,7.48" }, + { "Bad Hersfeld", "50.870,9.702" }, + { "Bad Tölz", "47.77,11.57" }, + { "Bamberg", "50.87,9.70" }, + { "Barweiler", "50.35,6.98" }, + { "Bayreuth", "49.95,11.56" }, + { "Bedburg", "50.98,6.57" }, + { "Bergen auf Rügen", "54.42,13.44" }, + { "Bergisch-Gladbach", "49.94,11.57" }, + { "Berlin", "52.52,13.40" }, + { "Bielefeld", "52.03,8.53" }, + { "Bitburg", "49.96,6.52" }, + { "Blexen", "49.96,6.52" }, + { "Bonn", "50.73,7.09" }, + { "Bottrop", "51.52,6.94" }, + { "Brandenburg", "52.41,12.53" }, + { "Braunschweig", "52.26,10.52" }, + { "Bremen", "53.07,8.80" }, + { "Bremerhaven", "53.53,8.58" }, + { "Brüggen", "51.03,6.33" }, + { "Brunsbüttel", "53.89,9.13" }, + { "Bückeburg", "52.25,9.05" }, + { "Büttgen", "51.19,6.60" }, + { "Celle", "52.25,9.05" }, + { "Chemnitz", "50.82,12.92" }, + { "Cloppenburg", "50.82,12.92" }, + { "Coburg", "50.26,10.96" }, + { "Cottbus", "51.75,14.33" }, + { "Cuxhaven", "53.85,8.68" }, + { "Dachau", "48.26,11.43" }, + { "Darmstadt", "49.87,8.65" }, + { "Deggendorf", "48.84,12.95" }, + { "Delmenhorst", "53.05,8.63" }, + { "Dessau", "51.82,12.24" }, + { "Detmold", "51.93,8.86" }, + { "Döbeln", "51.12,13.11" }, + { "Donaueschingen", "47.95,8.49" }, + { "Dortmund", "51.51,7.46" }, + { "Dresden", "51.05,13.73" }, + { "Duhnen", "53.88,8.64" }, + { "Duisburg", "51.43,6.76" }, + { "Düsseldorf", "51.22,6.77" }, + { "Ebersberg", "48.07,11.96" }, + { "Eberswalde", "52.837,13.788" }, + { "Eckernförde", "54.469,9.838" }, + { "Eggenfelden", "48.40,12.75" }, + { "Eichstätt", "48.89,11.18" }, + { "Elmshorn", "53.75,9.66" }, + { "Emden", "53.35,7.20" }, + { "Erding", "48.31,11.91" }, + { "Erfurt", "50.98,11.02" }, + { "Erkrath", "51.22,6.91" }, + { "Erlangen", "49.58,11.01" }, + { "Eschlkam", "49.29,12.91" }, + { "Eschwege", "51.18,10.03" }, + { "Essen", "51.45,7.01" }, + { "Esslingen", "48.74,9.32" }, + { "Euskirchen", "50.65,6.78" }, + { "Eutin", "54.13,10.60" }, + { "Falkensee", "52.56,13.07" }, + { "Feucht", "49.37,11.21" }, + { "Flensburg", "54.79,9.44" }, + { "Frankfurt am Main", "50.11,8.68" }, + { "Frankfurt an der Oder", "52.350,14.550" }, + { "Freiburg", "47.99,7.84" }, + { "Freigericht", "50.142,9.166" }, + { "Freising", "48.40,11.74" }, + { "Freudenstadt", "48.46,8.41" }, + { "Freyung", "48.80,13.54" }, + { "Friedrichshafen", "47.66,9.48" }, + { "Friesoythe", "53.02,7.85" }, + { "Fritzlar", "51.13,9.27" }, + { "Fulda", "50.55,9.68" }, + { "Fürstenfeldbruck", "48.17,11.24" }, + { "Fürth", "49.47,10.98" }, + { "Garmisch-Partenkirchen", "47.49,11.10" }, + { "Geilenkirchen", "50.97,6.12" }, + { "Gelnhausen", "50.20,9.19" }, + { "Gelsenkirchen", "51.52,7.09" }, + { "Gera", "50.89,12.08" }, + { "Geretsried", "47.86,11.49" }, + { "Germersheim", "49.21,8.37" }, + { "Gettorf", "54.41,9.98" }, + { "Gießen", "50.58,8.68" }, + { "Glauchau", "50.82,12.55" }, + { "Göppingen", "48.71,9.65" }, + { "Görlitz", "51.15,14.97" }, + { "Göttingen", "51.54,9.92" }, + { "Grafenau", "48.86,13.39" }, + { "Grafenwöhr", "49.71,11.91" }, + { "Greifswald", "54.09,13.39" }, + { "Grünberg", "50.59,8.96" }, + { "Gütersloh", "51.90,8.39" }, + { "Hagen", "51.37,7.46" }, + { "Hahn", "49.96,7.27" }, + { "Halle (Saale)", "51.497,11.969" }, + { "Halle (Westfalen)", "52.06,8.36" }, + { "Hamburg", "53.55,9.99" }, + { "Hamm", "51.67,7.82" }, + { "Hanau", "50.13,8.93" }, + { "Hannover", "52.38,9.73" }, + { "Harrislee", "54.80,9.39" }, + { "Heidelberg", "49.40,8.67" }, + { "Heilbronn", "49.14,9.21" }, + { "Helgoland", "54.18,7.89" }, + { "Hennigsdorf", "52.63,13.20" }, + { "Herne", "51.54,7.20" }, + { "Hilden", "51.17,6.93" }, + { "Hildesheim", "52.15,9.96" }, + { "Hinte", "53.41,7.20" }, + { "Hochheim", "50.01,8.36" }, + { "Hockenheimring", "49.33,8.57" }, + { "Hof", "50.31,11.91" }, + { "Holzkirchen", "47.88,11.70" }, + { "Hosten", "49.89,6.62" }, + { "Hürth", "50.88,6.89" }, + { "Husby", "54.50,9.48" }, + { "Husum", "54.48,9.06" }, + { "Idar-Oberstein", "49.71,7.31" }, + { "Ingolstadt", "48.77,11.43" }, + { "Iserlohn", "51.38,7.70" }, + { "Itzehoe", "53.93,9.51" }, + { "Jever", "53.57,7.90" }, + { "Jülich", "50.92,6.36" }, + { "Kall", "50.54,6.56" }, + { "Karlsruhe", "49.01,8.40" }, + { "Kassel", "51.31,9.48" }, + { "Kaufbeuren", "47.88,10.63" }, + { "Kempten", "47.73,10.32" }, + { "Kiel", "54.32,10.12" }, + { "Kitzingen", "49.73,10.15" }, + { "Koblenz", "50.36,7.59" }, + { "Köln", "50.94,6.96" }, + { "Konstanz", "47.68,9.17" }, + { "Krefeld", "51.34,6.59" }, + { "Kronshagen", "54.34,10.09" }, + { "Krumbach", "48.25,10.37" }, + { "Laarbruch", "51.60,6.15" }, + { "Lahr", "48.33,7.87" }, + { "Landshut", "48.54,12.15" }, + { "Langenhagen", "52.45,9.74" }, + { "Lausitzring", "51.54,13.89" }, + { "Lechfeld", "48.19,10.86" }, + { "Leck", "54.77,8.98" }, + { "Leer", "53.24,7.47" }, + { "Leipzig", "51.34,12.37" }, + { "Leverkusen", "51.05,7.02" }, + { "Lindenberg", "47.60,9.89" }, + { "List", "55.02,8.43" }, + { "Lübeck", "53.87,10.69" }, + { "Lüchow", "52.97,11.15" }, + { "Luckenwalde", "52.09,13.16" }, + { "Ludwigsburg", "48.89,9.20" }, + { "Ludwigshafen", "49.48,8.45" }, + { "Lüneburg", "53.25,10.41" }, + { "Magdeburg", "52.12,11.63" }, + { "Mainz", "49.99,8.25" }, + { "Mannheim", "49.49,8.47" }, + { "Marburg", "50.80,8.77" }, + { "Marienfelde", "52.42,13.37" }, + { "Marktbreit", "49.67,10.15" }, + { "Meiningen", "50.57,10.42" }, + { "Memmingen", "47.98,10.18" }, + { "Meppen", "52.70,7.30" }, + { "Merzig", "49.45,6.64" }, + { "Minden", "52.30,8.89" }, + { "Mönchengladbach", "51.18,6.44" }, + { "Mühldorf", "48.25,12.52" }, + { "München", "48.14,11.58" }, + { "Münster", "51.96,7.63" }, + { "Murnau", "47.68,11.20" }, + { "Mylau", "50.62,12.26" }, + { "Naumburg (Saale)", "51.15,11.82" }, + { "Neuberg", "48.11,12.12" }, + { "Neubrandenburg", "53.57,13.28" }, + { "Neumarkt", "49.28,11.47" }, + { "Neumünster", "54.07,9.98" }, + { "Neunkirchen", "49.35,7.19" }, + { "Neuruppin", "52.92,12.80" }, + { "Neuss", "51.20,6.69" }, + { "Neuwied", "50.44,7.47" }, + { "Niendorf (Ostsee)", "53.99,10.83" }, + { "Norden", "53.60,7.20" }, + { "Nordenham", "53.50,8.49" }, + { "Norderney", "53.71,7.16" }, + { "Nordhausen", "51.50,10" }, + { "Nordhausen", "51.50,10" }, + { "Nordheide", "53.12,8.46" }, + { "Nordhorn", "52.43,7.07" }, + { "Nördlingen", "48.85,10.49" }, + { "Nürburgring", "50.34,6.95" }, + { "Oberhausen", "51.50,6.86" }, + { "Oberpfaffenhofen", "48.07,11.26" }, + { "Oberstdorf", "47.41,10.28" }, + { "Ochsenfurt", "49.66,10.07" }, + { "Oeversee", "54.70,9.43" }, + { "Offenbach", "50.10,8.78" }, + { "Oldenburg", "53.14,8.21" }, + { "Oldersum", "53.33,7.34" }, + { "Oranienburg", "52.75,13.24" }, + { "Osnabrück", "52.28,8.05" }, + { "Otterndorf", "53.81,8.90" }, + { "Paderborn", "51.72,8.76" }, + { "Passau", "48.57,13" }, + { "Peine", "52.32,10.24" }, + { "Pfaffenhofen", "48.52,11.50" }, + { "Pfarrkirchen", "48.42,12.94" }, + { "Pforzheim", "48.89,8.69" }, + { "Pinneberg", "53.65,9.79" }, + { "Pirmasens", "49.20,7.60" }, + { "Plauen", "50.50,12.14" }, + { "Pocking", "48.40,13.32" }, + { "Potsdam", "52.39,13.06" }, + { "Prenzlau", "53.32,13.86" }, + { "Quickborn", "53.73,9.91" }, + { "Rastede", "53.24,8.20" }, + { "Recklinghausen", "51.61,7.20" }, + { "Regensburg", "49.01,12.10" }, + { "Remscheid", "51.18,7.19" }, + { "Rendsburg", "54.31,9.66" }, + { "Rennerod", "50.61,8.07" }, + { "Rosenheim", "47.86,12.12" }, + { "Rostock", "54.09,12.10" }, + { "Rüsselsheim", "50.00,8.42" }, + { "Saarbrücken", "49.230,7.000" }, + { "Sahlenburg", "53.870,8.630" }, + { "Salzgitter", "52.080,10.330" }, + { "Salzwedel", "52.850,11.150" }, + { "Schiffdorf", "53.530,8.650" }, + { "Schleswig", "54.520,9.550" }, + { "Schrobenhausen", "48.550,11.270" }, + { "Schwabach", "49.330,11.030" }, + { "Schwäbisch Hall", "49.110,9.730" }, + { "Schweinfurt", "50.050,10.230" }, + { "Schwerin", "53.630,11.380" }, + { "Siegburg", "50.800,7.200" }, + { "Siegen", "50.870,8.030" }, + { "Solingen", "51.180,7.080" }, + { "Starnberg", "48.000,11.350" }, + { "Straubing", "48.880,12.570" }, + { "Stuttgart", "48.770,9.180" }, + { "Sulingen", "52.680,8.800" }, + { "Sylt", "54.880,8.350" }, + { "Tönning", "54.320,8.950" }, + { "Traunstein", "47.87,12.62" }, + { "Travemünde", "53.970,10.870" }, + { "Trier", "49.750,6.630" }, + { "Tübingen", "48.530,9.050" }, + { "Ulm", "48.400,10.000" }, + { "Varel", "53.18,9.49" }, + { "Veitsbronn", "49.520,10.880" }, + { "Villingen-Schwenningen", "48.070,8.450" }, + { "Vilsbiburg", "48.450,12.350" }, + { "Vilshofen", "49.23,12.04" }, + { "Waldkirchen/Bayr.-Wald", "48.730,13.600" }, + { "Wallsbüll", "54.580,9.000" }, + { "Warnemünde", "54.170,12.080" }, + { "Weiden", "49.680,12.160" }, + { "Weimar", "50.980,11.320" }, + { "Weißenburg/Bayern", "49.030,10.980" }, + { "Wernigerode", "51.830,10.780" }, + { "Westerland/Sylt", "54.900,8.300" }, + { "Westerstede", "53.250,7.930" }, + { "Wetzlar", "50.550,8.500" }, + { "Wiesbaden", "50.080,8.250" }, + { "Wilhelmshaven", "53.520,8.130" }, + { "Wittenberge", "53.000,11.750" }, + { "Wittingen", "52.730,10.720" }, + { "Wolfsburg", "52.430,10.800" }, + { "Worms", "49.61,8.31" }, + { "Wuppertal", "51.270,7.180" }, + { "Würzburg", "49.790,9.940" }, + { "Zeven", "53.300,9.280" }, + { "Zirndorf", "49.450,10.950" }, + { "Zwickau", "50.720,12.500" } +}; + +#define WEATHER_DEUTSCHLAND_LOCATION_OPTION_COUNT (sizeof(WEATHER_DEUTSCHLAND_LOCATION_OPTIONS)/sizeof(weather_loc)) + +#endif diff --git a/src/gui/weather_locations.h b/src/gui/weather_locations.h index 184a26304..577031d46 100644 --- a/src/gui/weather_locations.h +++ b/src/gui/weather_locations.h @@ -19,300 +19,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#ifndef _WEATHER_LOCATIONS_ +#define _WEATHER_LOCATIONS_ + struct weather_loc { const char *key; const std::string value; }; -// locations and coords taken from tuxwetter plugin -const weather_loc WEATHER_LOCATION_OPTIONS[] = -{ - { "Aachen", "50.77,6.13" }, - { "Ahaus", "52.07,7.00" }, - { "Ahrensburg", "53.06,10.25" }, - { "Allendorf", "51.28,7.95" }, - { "Alsenz", "49.72,7.82" }, - { "Altenbruch", "53.82,8.77" }, - { "Amberg", "49.44,11.86" }, - { "Ansbach", "49.30,10.58" }, - { "Aschaffenburg", "49.97,9.15" }, - { "Augsburg", "48.37,10.88" }, - { "Aurich", "53.47,7.48" }, - { "Bad Hersfeld", "50.870,9.702" }, - { "Bad Tölz", "47.77,11.57" }, - { "Bamberg", "50.87,9.70" }, - { "Barweiler", "50.35,6.98" }, - { "Bayreuth", "49.95,11.56" }, - { "Bedburg", "50.98,6.57" }, - { "Bergen auf Rügen", "54.42,13.44" }, - { "Bergisch-Gladbach", "49.94,11.57" }, - { "Berlin", "52.52,13.40" }, - { "Bielefeld", "52.03,8.53" }, - { "Bitburg", "49.96,6.52" }, - { "Blexen", "49.96,6.52" }, - { "Bonn", "50.73,7.09" }, - { "Bottrop", "51.52,6.94" }, - { "Brandenburg", "52.41,12.53" }, - { "Braunschweig", "52.26,10.52" }, - { "Bremen", "53.07,8.80" }, - { "Bremerhaven", "53.53,8.58" }, - { "Brüggen", "51.03,6.33" }, - { "Brunsbüttel", "53.89,9.13" }, - { "Bückeburg", "52.25,9.05" }, - { "Büttgen", "51.19,6.60" }, - { "Celle", "52.25,9.05" }, - { "Chemnitz", "50.82,12.92" }, - { "Cloppenburg", "50.82,12.92" }, - { "Coburg", "50.26,10.96" }, - { "Cottbus", "51.75,14.33" }, - { "Cuxhaven", "53.85,8.68" }, - { "Dachau", "48.26,11.43" }, - { "Darmstadt", "49.87,8.65" }, - { "Deggendorf", "48.84,12.95" }, - { "Delmenhorst", "53.05,8.63" }, - { "Dessau", "51.82,12.24" }, - { "Detmold", "51.93,8.86" }, - { "Döbeln", "51.12,13.11" }, - { "Donaueschingen", "47.95,8.49" }, - { "Dortmund", "51.51,7.46" }, - { "Dresden", "51.05,13.73" }, - { "Duhnen", "53.88,8.64" }, - { "Duisburg", "51.43,6.76" }, - { "Düsseldorf", "51.22,6.77" }, - { "Ebersberg", "48.07,11.96" }, - { "Eberswalde", "52.837,13.788" }, - { "Eckernförde", "54.469,9.838" }, - { "Eggenfelden", "48.40,12.75" }, - { "Eichstätt", "48.89,11.18" }, - { "Elmshorn", "53.75,9.66" }, - { "Emden", "53.35,7.20" }, - { "Erding", "48.31,11.91" }, - { "Erfurt", "50.98,11.02" }, - { "Erkrath", "51.22,6.91" }, - { "Erlangen", "49.58,11.01" }, - { "Eschlkam", "49.29,12.91" }, - { "Eschwege", "51.18,10.03" }, - { "Essen", "51.45,7.01" }, - { "Esslingen", "48.74,9.32" }, - { "Euskirchen", "50.65,6.78" }, - { "Eutin", "54.13,10.60" }, - { "Falkensee", "52.56,13.07" }, - { "Feucht", "49.37,11.21" }, - { "Flensburg", "54.79,9.44" }, - { "Frankfurt am Main", "50.11,8.68" }, - { "Frankfurt an der Oder", "52.350,14.550" }, - { "Freiburg", "47.99,7.84" }, - { "Freigericht", "50.142,9.166" }, - { "Freising", "48.40,11.74" }, - { "Freudenstadt", "48.46,8.41" }, - { "Freyung", "48.80,13.54" }, - { "Friedrichshafen", "47.66,9.48" }, - { "Friesoythe", "53.02,7.85" }, - { "Fritzlar", "51.13,9.27" }, - { "Fulda", "50.55,9.68" }, - { "Fürstenfeldbruck", "48.17,11.24" }, - { "Fürth", "49.47,10.98" }, - { "Garmisch-Partenkirchen", "47.49,11.10" }, - { "Geilenkirchen", "50.97,6.12" }, - { "Gelnhausen", "50.20,9.19" }, - { "Gelsenkirchen", "51.52,7.09" }, - { "Gera", "50.89,12.08" }, - { "Geretsried", "47.86,11.49" }, - { "Germersheim", "49.21,8.37" }, - { "Gettorf", "54.41,9.98" }, - { "Gießen", "50.58,8.68" }, - { "Glauchau", "50.82,12.55" }, - { "Göppingen", "48.71,9.65" }, - { "Görlitz", "51.15,14.97" }, - { "Göttingen", "51.54,9.92" }, - { "Grafenau", "48.86,13.39" }, - { "Grafenwöhr", "49.71,11.91" }, - { "Greifswald", "54.09,13.39" }, - { "Grünberg", "50.59,8.96" }, - { "Gütersloh", "51.90,8.39" }, - { "Hagen", "51.37,7.46" }, - { "Hahn", "49.96,7.27" }, - { "Halle (Saale)", "51.497,11.969" }, - { "Halle (Westfalen)", "52.06,8.36" }, - { "Hamburg", "53.55,9.99" }, - { "Hamm", "51.67,7.82" }, - { "Hanau", "50.13,8.93" }, - { "Hannover", "52.38,9.73" }, - { "Harrislee", "54.80,9.39" }, - { "Heidelberg", "49.40,8.67" }, - { "Heilbronn", "49.14,9.21" }, - { "Helgoland", "54.18,7.89" }, - { "Hennigsdorf", "52.63,13.20" }, - { "Herne", "51.54,7.20" }, - { "Hilden", "51.17,6.93" }, - { "Hildesheim", "52.15,9.96" }, - { "Hinte", "53.41,7.20" }, - { "Hochheim", "50.01,8.36" }, - { "Hockenheimring", "49.33,8.57" }, - { "Hof", "50.31,11.91" }, - { "Holzkirchen", "47.88,11.70" }, - { "Hosten", "49.89,6.62" }, - { "Hürth", "50.88,6.89" }, - { "Husby", "54.50,9.48" }, - { "Husum", "54.48,9.06" }, - { "Idar-Oberstein", "49.71,7.31" }, - { "Ingolstadt", "48.77,11.43" }, - { "Iserlohn", "51.38,7.70" }, - { "Itzehoe", "53.93,9.51" }, - { "Jever", "53.57,7.90" }, - { "Jülich", "50.92,6.36" }, - { "Kall", "50.54,6.56" }, - { "Karlsruhe", "49.01,8.40" }, - { "Kassel", "51.31,9.48" }, - { "Kaufbeuren", "47.88,10.63" }, - { "Kempten", "47.73,10.32" }, - { "Kiel", "54.32,10.12" }, - { "Kitzingen", "49.73,10.15" }, - { "Koblenz", "50.36,7.59" }, - { "Köln", "50.94,6.96" }, - { "Konstanz", "47.68,9.17" }, - { "Krefeld", "51.34,6.59" }, - { "Kronshagen", "54.34,10.09" }, - { "Krumbach", "48.25,10.37" }, - { "Laarbruch", "51.60,6.15" }, - { "Lahr", "48.33,7.87" }, - { "Landshut", "48.54,12.15" }, - { "Langenhagen", "52.45,9.74" }, - { "Lausitzring", "51.54,13.89" }, - { "Lechfeld", "48.19,10.86" }, - { "Leck", "54.77,8.98" }, - { "Leer", "53.24,7.47" }, - { "Leipzig", "51.34,12.37" }, - { "Leverkusen", "51.05,7.02" }, - { "Lindenberg", "47.60,9.89" }, - { "List", "55.02,8.43" }, - { "Lübeck", "53.87,10.69" }, - { "Lüchow", "52.97,11.15" }, - { "Luckenwalde", "52.09,13.16" }, - { "Ludwigsburg", "48.89,9.20" }, - { "Ludwigshafen", "49.48,8.45" }, - { "Lüneburg", "53.25,10.41" }, - { "Magdeburg", "52.12,11.63" }, - { "Mainz", "49.99,8.25" }, - { "Mannheim", "49.49,8.47" }, - { "Marburg", "50.80,8.77" }, - { "Marienfelde", "52.42,13.37" }, - { "Marktbreit", "49.67,10.15" }, - { "Meiningen", "50.57,10.42" }, - { "Memmingen", "47.98,10.18" }, - { "Meppen", "52.70,7.30" }, - { "Merzig", "49.45,6.64" }, - { "Minden", "52.30,8.89" }, - { "Mönchengladbach", "51.18,6.44" }, - { "Mühldorf", "48.25,12.52" }, - { "München", "48.14,11.58" }, - { "Münster", "51.96,7.63" }, - { "Murnau", "47.68,11.20" }, - { "Mylau", "50.62,12.26" }, - { "Naumburg (Saale)", "51.15,11.82" }, - { "Neuberg", "48.11,12.12" }, - { "Neubrandenburg", "53.57,13.28" }, - { "Neumarkt", "49.28,11.47" }, - { "Neumünster", "54.07,9.98" }, - { "Neunkirchen", "49.35,7.19" }, - { "Neuruppin", "52.92,12.80" }, - { "Neuss", "51.20,6.69" }, - { "Neuwied", "50.44,7.47" }, - { "Niendorf (Ostsee)", "53.99,10.83" }, - { "Norden", "53.60,7.20" }, - { "Nordenham", "53.50,8.49" }, - { "Norderney", "53.71,7.16" }, - { "Nordhausen", "51.50,10" }, - { "Nordhausen", "51.50,10" }, - { "Nordheide", "53.12,8.46" }, - { "Nordhorn", "52.43,7.07" }, - { "Nördlingen", "48.85,10.49" }, - { "Nürburgring", "50.34,6.95" }, - { "Oberhausen", "51.50,6.86" }, - { "Oberpfaffenhofen", "48.07,11.26" }, - { "Oberstdorf", "47.41,10.28" }, - { "Ochsenfurt", "49.66,10.07" }, - { "Oeversee", "54.70,9.43" }, - { "Offenbach", "50.10,8.78" }, - { "Oldenburg", "53.14,8.21" }, - { "Oldersum", "53.33,7.34" }, - { "Oranienburg", "52.75,13.24" }, - { "Osnabrück", "52.28,8.05" }, - { "Otterndorf", "53.81,8.90" }, - { "Paderborn", "51.72,8.76" }, - { "Passau", "48.57,13" }, - { "Peine", "52.32,10.24" }, - { "Pfaffenhofen", "48.52,11.50" }, - { "Pfarrkirchen", "48.42,12.94" }, - { "Pforzheim", "48.89,8.69" }, - { "Pinneberg", "53.65,9.79" }, - { "Pirmasens", "49.20,7.60" }, - { "Plauen", "50.50,12.14" }, - { "Pocking", "48.40,13.32" }, - { "Potsdam", "52.39,13.06" }, - { "Prenzlau", "53.32,13.86" }, - { "Quickborn", "53.73,9.91" }, - { "Rastede", "53.24,8.20" }, - { "Recklinghausen", "51.61,7.20" }, - { "Regensburg", "49.01,12.10" }, - { "Remscheid", "51.18,7.19" }, - { "Rendsburg", "54.31,9.66" }, - { "Rennerod", "50.61,8.07" }, - { "Rosenheim", "47.86,12.12" }, - { "Rostock", "54.09,12.10" }, - { "Rüsselsheim", "50.00,8.42" }, - { "Saarbrücken", "49.230,7.000" }, - { "Sahlenburg", "53.870,8.630" }, - { "Salzgitter", "52.080,10.330" }, - { "Salzwedel", "52.850,11.150" }, - { "Schiffdorf", "53.530,8.650" }, - { "Schleswig", "54.520,9.550" }, - { "Schrobenhausen", "48.550,11.270" }, - { "Schwabach", "49.330,11.030" }, - { "Schwäbisch Hall", "49.110,9.730" }, - { "Schweinfurt", "50.050,10.230" }, - { "Schwerin", "53.630,11.380" }, - { "Siegburg", "50.800,7.200" }, - { "Siegen", "50.870,8.030" }, - { "Solingen", "51.180,7.080" }, - { "Starnberg", "48.000,11.350" }, - { "Straubing", "48.880,12.570" }, - { "Stuttgart", "48.770,9.180" }, - { "Sulingen", "52.680,8.800" }, - { "Sylt", "54.880,8.350" }, - { "Tönning", "54.320,8.950" }, - { "Traunstein", "47.87,12.62" }, - { "Travemünde", "53.970,10.870" }, - { "Trier", "49.750,6.630" }, - { "Tübingen", "48.530,9.050" }, - { "Ulm", "48.400,10.000" }, - { "Varel", "53.18,9.49" }, - { "Veitsbronn", "49.520,10.880" }, - { "Villingen-Schwenningen", "48.070,8.450" }, - { "Vilsbiburg", "48.450,12.350" }, - { "Vilshofen", "49.23,12.04" }, - { "Waldkirchen/Bayr.-Wald", "48.730,13.600" }, - { "Wallsbüll", "54.580,9.000" }, - { "Warnemünde", "54.170,12.080" }, - { "Weiden", "49.680,12.160" }, - { "Weimar", "50.980,11.320" }, - { "Weißenburg/Bayern", "49.030,10.980" }, - { "Wernigerode", "51.830,10.780" }, - { "Westerland/Sylt", "54.900,8.300" }, - { "Westerstede", "53.250,7.930" }, - { "Wetzlar", "50.550,8.500" }, - { "Wiesbaden", "50.080,8.250" }, - { "Wilhelmshaven", "53.520,8.130" }, - { "Wittenberge", "53.000,11.750" }, - { "Wittingen", "52.730,10.720" }, - { "Wolfsburg", "52.430,10.800" }, - { "Worms", "49.61,8.31" }, - { "Wuppertal", "51.270,7.180" }, - { "Würzburg", "49.790,9.940" }, - { "Zeven", "53.300,9.280" }, - { "Zirndorf", "49.450,10.950" }, - { "Zwickau", "50.720,12.500" } -}; - -#define WEATHER_LOCATION_OPTION_COUNT (sizeof(WEATHER_LOCATION_OPTIONS)/sizeof(weather_loc)) +#endif diff --git a/src/gui/weather_norway_locations.h b/src/gui/weather_norway_locations.h new file mode 100644 index 000000000..1ec86431e --- /dev/null +++ b/src/gui/weather_norway_locations.h @@ -0,0 +1,334 @@ +/* + Copyright (C) 2017,2018,2019 TangoCash + + “Powered by Dark Sky” https://darksky.net/poweredby/ + + License: GPLv2 + + 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; + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _WEATHER_NORWAY_LOCATION_H_ +#define _WEATHER_NORWAY_LOCATION_H_ + +#include "weather_locations.h" + +// locations and coords taken from http://www.tageo.com +const weather_loc WEATHER_NORWAY_LOCATION_OPTIONS[] = +{ + { "Agotnes", "60.410,5.020" }, + { "Akrehamn-vedavagen", "59.260,5.200" }, + { "Alesund", "62.480,6.200" }, + { "Algard-figgjo", "58.770,5.850" }, + { "Alta", "69.980,23.270" }, + { "Al", "60.640,8.560" }, + { "Amot-geithus", "59.900,9.900" }, + { "Andalsnes", "52.570,7.720" }, + { "Andebu", "59.330,10.080" }, + { "Andenes", "69.320,16.110" }, + { "Aneby", "60.080,10.870" }, + { "Ardalstangen", "61.240,7.700" }, + { "Arendal", "58.460,8.760" }, + { "Arnes", "60.130,11.470" }, + { "Aroysund", "59.180,10.460" }, + { "Asgardstrand", "59.350,10.460" }, + { "Askim", "59.580,11.160" }, + { "Askoy", "60.400,5.180" }, + { "As", "59.670,10.780" }, + { "Aulifeltet", "60.030,11.400" }, + { "Aursmoen", "59.920,11.430" }, + { "Batsfjord", "70.630,29.730" }, + { "Bergen", "60.380,5.340" }, + { "Biri", "60.970,10.500" }, + { "Birkeland", "58.330,8.230" }, + { "Bjerkvik", "68.560,17.520" }, + { "Bjervamoen", "59.320,9.130" }, + { "Bjorkelangen", "59.880,11.570" }, + { "Bjornevatn", "69.670,29.980" }, + { "Blakstad", "59.820,10.470" }, + { "Bodo", "67.290,14.370" }, + { "Borkenes", "68.780,16.180" }, + { "Bo", "59.420,9.060" }, + { "Brandbu-jaren", "60.430,10.470" }, + { "Brattvag", "62.600,6.450" }, + { "Brekstad", "63.680,9.680" }, + { "Bronnoysund", "65.470,12.220" }, + { "Brumunddal", "60.890,10.930" }, + { "Bryne", "58.730,5.650" }, + { "Buvika-ilhaugen", "63.250,10.070" }, + { "Dokka", "60.830,10.080" }, + { "Dombas", "62.080,9.130" }, + { "Drammen", "59.750,10.200" }, + { "Drobak", "59.670,10.650" }, + { "Egersund", "58.460,6.010" }, + { "Eidsvoll", "60.340,11.270" }, + { "Eike", "59.400,5.360" }, + { "Elnesvagen", "62.860,7.150" }, + { "Elverum", "60.890,11.540" }, + { "Espeland", "60.380,5.470" }, + { "Evje", "68.270,13.730" }, + { "Fagernes", "60.990,9.250" }, + { "Fagerstrand", "59.730,10.590" }, + { "Fanahammeren", "60.260,5.340" }, + { "Farsund", "58.090,6.780" }, + { "Fauske", "67.250,15.400" }, + { "Fetsund", "59.930,11.170" }, + { "Fevik", "58.380,8.700" }, + { "Finnsnes", "69.230,17.980" }, + { "Fitjar", "59.920,5.320" }, + { "Flateby", "59.830,11.170" }, + { "Flekkefjord", "58.310,6.680" }, + { "Flisa", "60.620,12.030" }, + { "Floro", "61.600,5.030" }, + { "Fordesfjorden", "59.420,5.400" }, + { "Forde", "61.460,5.870" }, + { "Fosnavag-leinstrand", "62.350,5.650" }, + { "Fredrikstad-sarpsborg", "59.240,10.940" }, + { "Frekhaug", "60.520,5.250" }, + { "Geilo", "60.520,8.200" }, + { "Gjovik", "60.790,10.650" }, + { "Gjusvik", "58.200,8.030" }, + { "Glomfjord", "66.820,13.970" }, + { "Gol", "60.700,8.950" }, + { "Gran-ringstad", "60.370,10.570" }, + { "Granrudmoen", "61.280,10.440" }, + { "Gravdal", "68.120,13.500" }, + { "Grimstad", "58.350,8.600" }, + { "Gronlund", "60.080,11.100" }, + { "Gronvoll", "60.120,10.940" }, + { "Grua", "60.270,10.670" }, + { "Gullhaug", "59.500,10.250" }, + { "Hagavik", "60.180,5.430" }, + { "Halden", "59.130,11.370" }, + { "Hamar", "60.810,11.080" }, + { "Hammerfest", "70.680,23.710" }, + { "Hareid", "62.370,6.030" }, + { "Harestua", "60.100,10.720" }, + { "Harstad", "68.810,16.520" }, + { "Haugesund", "59.420,5.270" }, + { "Hauge", "58.350,6.280" }, + { "Hauknes", "66.280,14.070" }, + { "Helgeroa-nevlunghamn", "59.000,9.850" }, + { "Hermannsverk-leikanger", "61.190,6.780" }, + { "Herre", "59.100,9.570" }, + { "Hesseng", "69.680,29.990" }, + { "Holmestrand", "59.500,10.310" }, + { "Hommelvik", "63.420,10.800" }, + { "Hommersak", "58.930,5.850" }, + { "Honefoss", "60.190,10.230" }, + { "Honningsvag", "70.980,25.980" }, + { "Horten", "59.420,10.470" }, + { "Hov", "60.710,10.360" }, + { "Hoyanger", "61.220,6.080" }, + { "Husnes", "59.870,5.770" }, + { "Hylkje", "60.510,5.350" }, + { "Indre arna", "60.420,5.480" }, + { "Innbygda", "61.320,12.270" }, + { "Jessheim", "60.150,11.180" }, + { "Jevnaker", "60.260,10.400" }, + { "Jorpeland", "59.020,6.050" }, + { "Jorstadmoen-faberg", "61.170,10.420" }, + { "Kabelvag", "68.210,14.480" }, + { "Kapp", "60.710,10.860" }, + { "Karasjok", "69.450,25.500" }, + { "Karlshus", "59.350,10.870" }, + { "Kautokeino", "68.980,23.130" }, + { "Kirkenaer", "60.470,12.050" }, + { "Kirkenes", "69.730,30.030" }, + { "Kjenner", "59.790,10.280" }, + { "Klaebu", "64.080,11.730" }, + { "Kleppe-verdalen", "58.780,5.640" }, + { "Klofta", "60.070,11.150" }, + { "Knarrevik-straume", "60.370,5.160" }, + { "Knarvik", "60.540,5.290" }, + { "Kolvereid", "64.850,11.600" }, + { "Kongsberg", "59.670,9.630" }, + { "Kongsvinger", "60.200,11.990" }, + { "Kopervik", "59.290,5.310" }, + { "Koppang", "61.570,11.070" }, + { "Kragero", "58.870,9.400" }, + { "Kristiansand", "58.150,7.990" }, + { "Kristiansund", "63.120,7.760" }, + { "Kvernaland", "58.790,5.730" }, + { "Kyrksaeterora", "63.280,9.100" }, + { "Lakselv", "70.050,24.930" }, + { "Larkollen", "59.330,10.670" }, + { "Larvik", "59.070,9.990" }, + { "Lauve-viksjord", "59.070,10.150" }, + { "Leirvik", "59.800,5.490" }, + { "Leknes", "68.160,13.600" }, + { "Lervik", "59.270,10.760" }, + { "Levanger", "63.750,11.320" }, + { "Lierbyen", "59.830,10.250" }, + { "Liknes", "58.320,58.320" }, + { "Lillehammer", "61.120,10.470" }, + { "Lillesand", "58.250,8.390" }, + { "Lodingen", "68.420,15.960" }, + { "Loding", "67.300,14.750" }, + { "Lopsmarka", "67.320,14.450" }, + { "Lostad", "60.110,10.930" }, + { "Loten", "60.810,11.330" }, + { "Lyefjell", "58.750,5.750" }, + { "Lyngdal", "58.150,7.100" }, + { "Maloy", "61.930,5.110" }, + { "Malvik", "63.430,10.680" }, + { "Mandal", "58.030,7.440" }, + { "Maura", "60.260,11.040" }, + { "Melbu", "68.510,14.800" }, + { "Melhus", "63.300,10.290" }, + { "Melsomvik", "59.230,10.340" }, + { "Moelv", "60.930,10.700" }, + { "Moi", "58.460,6.540" }, + { "Molde", "62.740,7.180" }, + { "Mosjoen", "65.840,13.220" }, + { "Moss", "59.430,10.680" }, + { "Mo i rana", "66.330,14.170" }, + { "Myre", "69.110,15.960" }, + { "Mysen", "59.560,11.330" }, + { "Naerbo", "58.670,5.650" }, + { "Namsos", "64.480,11.520" }, + { "Narvik", "68.450,17.420" }, + { "Nesbyen", "60.580,9.110" }, + { "Nesna", "66.210,13.030" }, + { "Nesoddtangen", "59.860,10.670" }, + { "Nodeland", "58.160,7.840" }, + { "Nordfjordeid", "61.900,6.000" }, + { "Nordstrand", "62.510,6.050" }, + { "Norheimsund", "60.370,6.140" }, + { "Notodden", "59.570,9.260" }, + { "Odda", "60.070,6.540" }, + { "Oppdal", "62.600,9.660" }, + { "Orje", "59.480,11.670" }, + { "Orkanger-fannrem", "63.300,9.860" }, + { "Ornes", "66.870,13.700" }, + { "Orsta", "62.210,6.140" }, + { "Oslo", "59.910,10.750" }, + { "Osoyro", "60.190,5.450" }, + { "Otta", "61.780,9.520" }, + { "Ovre ardal", "61.320,7.810" }, + { "Oystese", "60.400,6.210" }, + { "Porsgrunn-skien", "59.150,9.660" }, + { "Raholt", "60.270,11.180" }, + { "Rakkestad", "59.420,11.360" }, + { "Raufoss", "60.730,10.630" }, + { "Rena", "61.150,11.330" }, + { "Rensvik", "63.100,7.820" }, + { "Revetal-bergsasen", "59.360,10.280" }, + { "Ringebu", "61.550,10.110" }, + { "Risor", "58.730,9.220" }, + { "Rjukan", "59.880,8.560" }, + { "Roa-lunner", "60.300,10.620" }, + { "Rognan", "67.100,15.390" }, + { "Roros", "62.580,11.380" }, + { "Rorvik", "64.870,11.240" }, + { "Rotnes", "60.050,10.880" }, + { "Royken", "59.750,10.380" }, + { "Ryggebyen", "59.390,10.720" }, + { "Rypefjord", "70.630,23.670" }, + { "Saetre", "59.680,10.520" }, + { "Sagvag", "59.780,5.380" }, + { "Sandane", "61.780,6.220" }, + { "Sandefjord", "59.140,10.210" }, + { "Sande", "59.590,10.210" }, + { "Sandnessjoen", "66.020,12.630" }, + { "Sauda", "59.650,6.340" }, + { "Selvik", "59.570,10.270" }, + { "Sem", "59.290,10.300" }, + { "Setermoen", "68.890,18.330" }, + { "Siggerud", "59.810,10.880" }, + { "Silsand", "69.230,17.930" }, + { "Skalevik", "58.080,8.010" }, + { "Skarnes", "60.250,11.700" }, + { "Skei-surnadalsora", "62.970,8.650" }, + { "Skiptvet", "59.460,11.180" }, + { "Ski", "59.720,10.830" }, + { "Skjeberg", "59.220,11.200" }, + { "Skjervoy", "70.050,21.000" }, + { "Skjonhaug", "59.640,11.310" }, + { "Skodje", "62.510,6.670" }, + { "Skogn", "63.710,11.230" }, + { "Skoppum", "59.380,10.420" }, + { "Skotterud", "59.980,12.130" }, + { "Skreia", "60.650,10.940" }, + { "Skudeneshamn", "59.160,5.250" }, + { "Skulestadmoen", "60.690,6.450" }, + { "Softeland", "60.250,5.430" }, + { "Sogndalsfjora", "60.250,5.440" }, + { "Sogne", "58.100,7.780" }, + { "Son-store", "4700,59.520" }, + { "Sorreisa", "69.150,18.120" }, + { "Sortland", "68.710,15.380" }, + { "Sorumsand", "59.990,11.260" }, + { "Spetalen", "60.180,11.900" }, + { "Spydeberg", "59.620,11.090" }, + { "Stange", "60.730,11.220" }, + { "Stavanger", "58.970,5.710" }, + { "Stavern", "59.000,10.030" }, + { "Steinkjer", "64.020,11.480" }, + { "Steinsasen", "60.090,10.270" }, + { "Stjordalshalsen", "63.480,10.940" }, + { "Stokke", "59.230,10.310" }, + { "Stokmarknes", "68.560,14.910" }, + { "Storen", "63.040,10.260" }, + { "Storslett", "69.770,21.070" }, + { "Stranda", "62.320,6.930" }, + { "Stryn", "61.920,6.780" }, + { "Sunde-valen", "59.850,5.710" }, + { "Sunndalsora", "62.680,8.580" }, + { "Svelvik", "59.620,10.410" }, + { "Svolvaer", "68.260,14.550" }, + { "Svortland", "59.770,5.120" }, + { "Sykkylven", "62.400,6.590" }, + { "Tananger", "58.940,5.600" }, + { "Tau", "59.080,5.920" }, + { "Teigebyen", "60.230,11.000" }, + { "Tjome", "59.130,10.390" }, + { "Tofte", "59.570,10.610" }, + { "Togrenda", "59.740,10.750" }, + { "Tomter", "59.670,11.010" }, + { "Tonsberg", "59.270,10.420" }, + { "Tranby", "59.790,10.280" }, + { "Tromso", "69.660,18.940" }, + { "Trondheim", "63.440,10.400" }, + { "Tvedestrand", "58.620,8.930" }, + { "Tveit", "58.260,8.130" }, + { "Tynset", "62.280,10.770" }, + { "Ulefoss", "59.280,9.260" }, + { "Ulsteinvik", "62.340,5.870" }, + { "Vadfoss-helle", "58.900,9.360" }, + { "Vadso", "70.090,29.740" }, + { "Vagamo", "61.880,9.110" }, + { "Vang", "60.210,10.330" }, + { "Vanse", "58.100,6.690" }, + { "Vardo", "70.390,31.060" }, + { "Varhaug", "58.630,5.650" }, + { "Vatne", "62.560,6.620" }, + { "Vear", "59.250,10.360" }, + { "Vennesla", "58.260,7.960" }, + { "Verdalsora", "63.800,11.490" }, + { "Vestby", "59.600,10.740" }, + { "Vestfossen", "58.750,9.870" }, + { "Vestnes", "62.620,7.080" }, + { "Vigrestad", "58.580,5.680" }, + { "Vikersund", "59.990,10.010" }, + { "Vinstra", "61.600,9.750" }, + { "Volda", "62.150,6.070" }, + { "Vossevangen", "60.640,6.430" }, + { "Ytre arna", "60.470,5.430" }, + { "Ytre enebakk", "59.730,11.060" } +}; + +#define WEATHER_NORWAY_LOCATION_OPTION_COUNT (sizeof(WEATHER_NORWAY_LOCATION_OPTIONS)/sizeof(weather_loc)) + +#endif diff --git a/src/gui/widget/keyboard_input.cpp b/src/gui/widget/keyboard_input.cpp index 8605d2a29..4f36e3c2a 100644 --- a/src/gui/widget/keyboard_input.cpp +++ b/src/gui/widget/keyboard_input.cpp @@ -485,6 +485,9 @@ int CKeyboardInput::exec(CMenuTarget* parent, const std::string &) { changed = false; CVFD::getInstance()->showMenuText(1, inputString->c_str() , selected+1); +#ifdef ENABLE_GRAPHLCD + cGLCD::lockChannel(inputString->c_str(), "", 0); +#endif } g_RCInput->getMsgAbsoluteTimeout(&msg, &data, &timeoutEnd, true); @@ -588,6 +591,10 @@ int CKeyboardInput::exec(CMenuTarget* parent, const std::string &) OnAfterSave(); } +#ifdef ENABLE_GRAPHLCD + cGLCD::unlockChannel(); +#endif + return res; } diff --git a/src/gui/widget/menue.cpp b/src/gui/widget/menue.cpp index d59b759db..038af77ef 100644 --- a/src/gui/widget/menue.cpp +++ b/src/gui/widget/menue.cpp @@ -262,7 +262,7 @@ void CMenuItem::paintItemCaption(const bool select_mode, const char * right_text #ifdef ENABLE_GRAPHLCD if (g_settings.glcd_enable) - nGLCD::lockChannel(g_Locale->getText(LOCALE_MAINMENU_HEAD), graphlcd_text, 0); + cGLCD::lockChannel(g_Locale->getText(LOCALE_MAINMENU_HEAD), graphlcd_text, 0); #endif if (g_settings.lcd4l_support) LCD4l->CreateFile("/tmp/lcd/menu", lcd4l_text, g_settings.lcd4l_convert); @@ -1036,7 +1036,7 @@ int CMenuWidget::exec(CMenuTarget* parent, const std::string &) case (CRCInput::RC_ok): if (hasItem() && selected > -1 && (int)items.size() > selected) { #ifdef ENABLE_GRAPHLCD - nGLCD::unlockChannel(); + cGLCD::unlockChannel(); #endif LCD4l->RemoveFile("/tmp/lcd/menu"); @@ -1055,7 +1055,7 @@ int CMenuWidget::exec(CMenuTarget* parent, const std::string &) #ifdef ENABLE_GRAPHLCD if (g_settings.glcd_enable) - nGLCD::lockChannel(g_Locale->getText(LOCALE_MAINMENU_HEAD), item->graphlcd_text, 0); + cGLCD::lockChannel(g_Locale->getText(LOCALE_MAINMENU_HEAD), item->graphlcd_text, 0); #endif if (g_settings.lcd4l_support) LCD4l->CreateFile("/tmp/lcd/menu", item->lcd4l_text, g_settings.lcd4l_convert); @@ -1145,7 +1145,7 @@ int CMenuWidget::exec(CMenuTarget* parent, const std::string &) CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); #ifdef ENABLE_GRAPHLCD - nGLCD::unlockChannel(); + cGLCD::unlockChannel(); #endif LCD4l->RemoveFile("/tmp/lcd/menu"); diff --git a/src/gui/widget/stringinput.cpp b/src/gui/widget/stringinput.cpp index b29f4e080..fed248c07 100644 --- a/src/gui/widget/stringinput.cpp +++ b/src/gui/widget/stringinput.cpp @@ -412,6 +412,9 @@ int CStringInput::exec( CMenuTarget* parent, const std::string & ) if (*valueString != dispval) { CVFD::getInstance()->showMenuText(1,valueString->c_str() , selected+1); +#ifdef ENABLE_GRAPHLCD + cGLCD::lockChannel(valueString->c_str(), "", 0); +#endif dispval = *valueString; } @@ -535,6 +538,9 @@ int CStringInput::exec( CMenuTarget* parent, const std::string & ) { observ->changeNotify(name, (void *) valueString->c_str()); } +#ifdef ENABLE_GRAPHLCD + cGLCD::unlockChannel(); +#endif return res; } diff --git a/src/gui/widget/stringinput_ext.cpp b/src/gui/widget/stringinput_ext.cpp index 192440491..a9a665e65 100644 --- a/src/gui/widget/stringinput_ext.cpp +++ b/src/gui/widget/stringinput_ext.cpp @@ -196,6 +196,9 @@ int CExtendedInput::exec( CMenuTarget* parent, const std::string & ) if (*valueString != dispval) { CVFD::getInstance()->showMenuText(1, valueString->c_str(), selectedChar+1); +#ifdef ENABLE_GRAPHLCD + cGLCD::lockChannel(valueString->c_str(), "", 0); +#endif dispval = *valueString; } @@ -225,6 +228,9 @@ int CExtendedInput::exec( CMenuTarget* parent, const std::string & ) inputFields[oldSelectedChar]->paint(x+ offset, y+ hheight+ offset, false ); inputFields[selectedChar]->paint(x+ offset, y+ hheight+ offset, true ); CVFD::getInstance()->showMenuText(1, valueString->c_str(), selectedChar+1); +#ifdef ENABLE_GRAPHLCD + cGLCD::lockChannel(valueString->c_str(), "", 0); +#endif } } else if (msg==CRCInput::RC_right) { bool found = false; @@ -252,6 +258,9 @@ int CExtendedInput::exec( CMenuTarget* parent, const std::string & ) inputFields[oldSelectedChar]->paint(x+ offset, y+ hheight+ offset, false ); inputFields[selectedChar]->paint(x+ offset, y+ hheight+ offset, true ); CVFD::getInstance()->showMenuText(1, valueString->c_str(), selectedChar+1); +#ifdef ENABLE_GRAPHLCD + cGLCD::lockChannel(valueString->c_str(), "", 0); +#endif } } else if ( (*CRCInput::getUnicodeValue(msg)) || (msg == CRCInput::RC_red) || (msg == CRCInput::RC_green) || (msg == CRCInput::RC_blue) || (msg == CRCInput::RC_yellow) @@ -314,6 +323,10 @@ int CExtendedInput::exec( CMenuTarget* parent, const std::string & ) if ((observ) && (msg == CRCInput::RC_ok)) observ->changeNotify(name, (void *)valueString->c_str()); +#ifdef ENABLE_GRAPHLCD + cGLCD::unlockChannel(); +#endif + return res; } diff --git a/src/neutrino.cpp b/src/neutrino.cpp index a053336e0..8d66af892 100644 --- a/src/neutrino.cpp +++ b/src/neutrino.cpp @@ -75,6 +75,9 @@ #include "gui/favorites.h" #include "gui/filebrowser.h" #include "gui/followscreenings.h" +#ifdef ENABLE_GRAPHLCD +#include "gui/glcdthemes.h" +#endif #include "gui/hdd_menu.h" #include "gui/infoviewer.h" #include "gui/mediaplayer.h" @@ -359,6 +362,11 @@ int CNeutrinoApp::loadSetup(const char * fname) g_settings.theme_name = configfile.getString("theme_name", !access(NEUTRINO_SETTINGS_FILE, F_OK) ? MIGRATE_THEME_NAME : ""); CThemes::getInstance()->getTheme(configfile); +#ifdef ENABLE_GRAPHLCD + g_settings.glcd_theme_name = configfile.getString("glcd_theme_name", !access(NEUTRINO_SETTINGS_FILE, F_OK) ? MIGRATE_THEME_OLED_NAME : ""); + CGLCDThemes::getInstance()->getTheme(configfile); +#endif + //NI g_settings.inetradio_autostart = configfile.getInt32("inetradio_autostart" , 0); g_settings.lcd4l_support = configfile.getInt32("lcd4l_support" , 0); @@ -685,27 +693,17 @@ int CNeutrinoApp::loadSetup(const char * fname) #ifdef ENABLE_GRAPHLCD g_settings.glcd_enable = configfile.getInt32("glcd_enable", 1); - g_settings.glcd_color_fg = configfile.getInt32("glcd_color_fg", GLCD::cColor::White); - g_settings.glcd_color_bg = configfile.getInt32("glcd_color_bg", GLCD::cColor::Black); - g_settings.glcd_color_bar = configfile.getInt32("glcd_color_bar", GLCD::cColor::Gray); - g_settings.glcd_percent_channel = configfile.getInt32("glcd_percent_channel", 22); - g_settings.glcd_percent_epg = configfile.getInt32("glcd_percent_epg", 16); - g_settings.glcd_percent_bar = configfile.getInt32("glcd_percent_bar", 8); - g_settings.glcd_percent_time = configfile.getInt32("glcd_percent_time", 35); - g_settings.glcd_percent_time_standby = configfile.getInt32("glcd_percent_time_standby", 50); - g_settings.glcd_percent_logo = configfile.getInt32("glcd_percent_logo", 50); + + g_settings.glcd_time_in_standby = configfile.getInt32("glcd_time_in_standby", 1); + g_settings.glcd_standby_weather = configfile.getInt32("glcd_standby_weather", 1); + g_settings.glcd_mirror_osd = configfile.getInt32("glcd_mirror_osd", 0); g_settings.glcd_mirror_video = configfile.getInt32("glcd_mirror_video", 0); - g_settings.glcd_time_in_standby = configfile.getInt32("glcd_time_in_standby", 1); g_settings.glcd_show_logo = configfile.getInt32("glcd_show_logo", 1); - g_settings.glcd_font = configfile.getString("glcd_font", FONTDIR "/neutrino.ttf"); -#if BOXMODEL_VUUNO4KSE - g_settings.glcd_brightness = configfile.getInt32("glcd_brightness", 25); - g_settings.glcd_brightness_standby = configfile.getInt32("glcd_brightness_standby", 5); -#else - g_settings.glcd_brightness = configfile.getInt32("glcd_brightness", 75); - g_settings.glcd_brightness_standby = configfile.getInt32("glcd_brightness_standby", 45); -#endif + g_settings.glcd_brightness = configfile.getInt32("glcd_brightness", GLCD_DEFAULT_BRIGHTNESS); + g_settings.glcd_brightness_dim = configfile.getInt32("glcd_brightness_dim", GLCD_DEFAULT_BRIGHTNESS_DIM); + g_settings.glcd_brightness_standby = configfile.getInt32("glcd_brightness_standby", GLCD_DEFAULT_BRIGHTNESS_STANDBY); + g_settings.glcd_brightness_dim_time = configfile.getString("glcd_brightness_dim_time", GLCD_DEFAULT_BRIGHTNESS_DIM_TIME); #if BOXMODEL_VUUNO4KSE g_settings.glcd_scroll_speed = configfile.getInt32("glcd_scroll_speed", 1); #elif BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUULTIMO4K @@ -713,7 +711,7 @@ int CNeutrinoApp::loadSetup(const char * fname) #else g_settings.glcd_scroll_speed = configfile.getInt32("glcd_scroll_speed", 5); #endif - g_settings.glcd_selected_config = configfile.getInt32("glcd_selected_config", 0); + //g_settings.glcd_selected_config = configfile.getInt32("glcd_selected_config", 0); #endif //personalize @@ -1069,6 +1067,7 @@ int CNeutrinoApp::loadSetup(const char * fname) g_settings.weather_api_key = configfile.getString("weather_api_key", g_settings.weather_api_key.empty() ? "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" : g_settings.weather_api_key); #endif g_settings.weather_enabled = configfile.getInt32("weather_enabled", 1); + g_settings.weather_country = configfile.getInt32("weather_country", 0); g_settings.weather_enabled = g_settings.weather_enabled && CApiKey::check_weather_api_key(); g_settings.weather_location = configfile.getString("weather_location", "52.52,13.40" ); @@ -1430,6 +1429,11 @@ void CNeutrinoApp::saveSetup(const char * fname) CThemes::getInstance()->setTheme(configfile); configfile.setString( "theme_name", g_settings.theme_name ); +#ifdef ENABLE_GRAPHLCD + CGLCDThemes::getInstance()->setTheme(configfile); + configfile.setString( "glcd_theme_name", g_settings.glcd_theme_name ); +#endif + //NI configfile.setInt32("inetradio_autostart" , g_settings.inetradio_autostart); configfile.setInt32("lcd4l_support" , g_settings.lcd4l_support); @@ -1669,24 +1673,17 @@ void CNeutrinoApp::saveSetup(const char * fname) #ifdef ENABLE_GRAPHLCD configfile.setInt32("glcd_enable", g_settings.glcd_enable); - configfile.setInt32("glcd_color_fg", g_settings.glcd_color_fg); - configfile.setInt32("glcd_color_bg", g_settings.glcd_color_bg); - configfile.setInt32("glcd_color_bar", g_settings.glcd_color_bar); - configfile.setInt32("glcd_percent_channel", g_settings.glcd_percent_channel); - configfile.setInt32("glcd_percent_epg", g_settings.glcd_percent_epg); - configfile.setInt32("glcd_percent_bar", g_settings.glcd_percent_bar); - configfile.setInt32("glcd_percent_time", g_settings.glcd_percent_time); - configfile.setInt32("glcd_percent_time_standby", g_settings.glcd_percent_time_standby); - configfile.setInt32("glcd_percent_logo", g_settings.glcd_percent_logo); + configfile.setInt32("glcd_time_in_standby", g_settings.glcd_time_in_standby); + configfile.setInt32("glcd_standby_weather", g_settings.glcd_standby_weather); configfile.setInt32("glcd_mirror_osd", g_settings.glcd_mirror_osd); configfile.setInt32("glcd_mirror_video", g_settings.glcd_mirror_video); - configfile.setInt32("glcd_time_in_standby", g_settings.glcd_time_in_standby); configfile.setInt32("glcd_show_logo", g_settings.glcd_show_logo); - configfile.setString("glcd_font", g_settings.glcd_font); configfile.setInt32("glcd_brightness", g_settings.glcd_brightness); + configfile.setInt32("glcd_brightness_dim", g_settings.glcd_brightness_dim); configfile.setInt32("glcd_brightness_standby", g_settings.glcd_brightness_standby); configfile.setInt32("glcd_scroll_speed", g_settings.glcd_scroll_speed); - configfile.setInt32("glcd_selected_config", g_settings.glcd_selected_config); + configfile.setString("glcd_brightness_dim_time", g_settings.glcd_brightness_dim_time); + //configfile.setInt32("glcd_selected_config", g_settings.glcd_selected_config); #endif //personalize @@ -1935,7 +1932,7 @@ void CNeutrinoApp::saveSetup(const char * fname) configfile.setString( "weather_api_key", g_settings.weather_api_key ); #endif configfile.setInt32( "weather_enabled", g_settings.weather_enabled ); - + configfile.setInt32( "weather_country", g_settings.weather_country ); configfile.setString( "weather_location", g_settings.weather_location ); configfile.setString( "weather_city", g_settings.weather_city ); @@ -2293,36 +2290,51 @@ void CNeutrinoApp::SetChannelMode(int newmode) switch(newmode) { case LIST_MODE_FAV: - if (isRadioMode) + if (isRadioMode) { +#ifdef ENABLE_GRAPHLCD + cGLCD::MirrorOSD(false); +#endif bouquetList = RADIOfavList; - else + } else bouquetList = TVfavList; break; case LIST_MODE_SAT: - if (isRadioMode) + if (isRadioMode) { +#ifdef ENABLE_GRAPHLCD + cGLCD::MirrorOSD(false); +#endif bouquetList = RADIOsatList; - else + } else bouquetList = TVsatList; break; case LIST_MODE_WEB: - if (isRadioMode) + if (isRadioMode) { +#ifdef ENABLE_GRAPHLCD + cGLCD::MirrorOSD(false); +#endif bouquetList = RADIOwebList; - else + } else bouquetList = TVwebList; break; case LIST_MODE_ALL: - if (isRadioMode) + if (isRadioMode) { +#ifdef ENABLE_GRAPHLCD + cGLCD::MirrorOSD(false); +#endif bouquetList = RADIOallList; - else + } else bouquetList = TVallList; break; default: newmode = LIST_MODE_PROV; /* fall through */ case LIST_MODE_PROV: - if (isRadioMode) + if (isRadioMode) { +#ifdef ENABLE_GRAPHLCD + cGLCD::MirrorOSD(false); +#endif bouquetList = RADIObouquetList; - else + } else bouquetList = TVbouquetList; break; } @@ -2769,7 +2781,7 @@ TIMER_START(); CVFD::getInstance()->setScrollMode(g_settings.lcd_scroll); #ifdef ENABLE_GRAPHLCD - nGLCD::getInstance(); + cGLCD::getInstance(); #endif if (!scanSettings.loadSettings(NEUTRINO_SCAN_SETTINGS_FILE)) @@ -2951,6 +2963,13 @@ TIMER_START(); CVFD::getInstance()->showVolume(g_settings.current_volume, false); //CVFD::getInstance()->setMuted(current_muted); +#ifdef ENABLE_GRAPHLCD + if (current_muted) + cGLCD::lockIcon(cGLCD::MUTE); + else + cGLCD::unlockIcon(cGLCD::MUTE); +#endif + if (show_startwizard) { hintBox->hide(); CStartUpWizard startwizard; @@ -3433,7 +3452,7 @@ void CNeutrinoApp::RealRun() } #ifdef ENABLE_GRAPHLCD if (msg == NeutrinoMessages::EVT_CURRENTNEXT_EPG) { - nGLCD::Update(); + cGLCD::Update(); } #endif } @@ -3718,7 +3737,7 @@ int CNeutrinoApp::handleMsg(const neutrino_msg_t _msg, neutrino_msg_data_t data) CVFD::getInstance()->UpdateIcons(); #ifdef ENABLE_GRAPHLCD - nGLCD::Update(); + cGLCD::Update(); #endif g_RCInput->killTimer(scrambled_timer); if (mode != NeutrinoModes::mode_webtv) { @@ -3901,7 +3920,8 @@ int CNeutrinoApp::handleMsg(const neutrino_msg_t _msg, neutrino_msg_data_t data) //switch lcd off/on CVFD::getInstance()->togglePower(); #ifdef ENABLE_GRAPHLCD - nGLCD::TogglePower(); + if (g_settings.glcd_enable) + cGLCD::TogglePower(); #endif } else { @@ -4575,7 +4595,7 @@ void CNeutrinoApp::ExitRun(int exit_code) #ifdef ENABLE_GRAPHLCD if (exit_code == CNeutrinoApp::EXIT_SHUTDOWN) - nGLCD::SetBrightness(0); + cGLCD::SetBrightness(0); #endif Cleanup(); @@ -4746,7 +4766,7 @@ void CNeutrinoApp::standbyMode( bool bOnOff, bool fromDeepStandby ) fclose(f); #ifdef ENABLE_GRAPHLCD - nGLCD::StandbyMode(true); + cGLCD::StandbyMode(true); #endif CVFD::getInstance()->ShowText("Standby ..."); if( mode == NeutrinoModes::mode_scart ) { @@ -4841,7 +4861,8 @@ void CNeutrinoApp::standbyMode( bool bOnOff, bool fromDeepStandby ) g_RCInput->killTimer(fst_timer); #ifdef ENABLE_GRAPHLCD - nGLCD::StandbyMode(false); + cGLCD::Resume(); + cGLCD::StandbyMode(false); #endif if(init_cec_setting){ @@ -5287,7 +5308,7 @@ void stop_daemons(bool stopall, bool for_flash) tuxtxt_close(); #ifdef ENABLE_GRAPHLCD - nGLCD::Exit(); + cGLCD::Exit(); #endif if (g_Radiotext) { @@ -5622,7 +5643,7 @@ void CNeutrinoApp::StopSubtitles(bool enable_glcd_mirroring) } #ifdef ENABLE_GRAPHLCD if (enable_glcd_mirroring) - nGLCD::MirrorOSD(g_settings.glcd_mirror_osd); + cGLCD::MirrorOSD(g_settings.glcd_mirror_osd); #else (void) enable_glcd_mirroring; // avoid compiler warning #endif @@ -5634,7 +5655,7 @@ void CNeutrinoApp::StartSubtitles(bool show) { //printf("%s: %s\n", __FUNCTION__, show ? "Show" : "Not show"); #ifdef ENABLE_GRAPHLCD - nGLCD::MirrorOSD(false); + cGLCD::MirrorOSD(false); #endif if(!show) return; diff --git a/src/nhttpd/tuxboxapi/controlapi.cpp b/src/nhttpd/tuxboxapi/controlapi.cpp index 2da8f3f11..1ff9f7d3f 100644 --- a/src/nhttpd/tuxboxapi/controlapi.cpp +++ b/src/nhttpd/tuxboxapi/controlapi.cpp @@ -35,6 +35,7 @@ #include #include //for relodplugins #include +#include #include #include #include @@ -202,6 +203,9 @@ const CControlAPI::TyCgiCall CControlAPI::yCgiCallList[]= {"reloadchannels", &CControlAPI::ReloadChannelsCGI, ""}, #ifdef SCREENSHOT {"screenshot", &CControlAPI::ScreenshotCGI, ""}, +#endif +#ifdef ENABLE_GRAPHLCD + {"glcdscreenshot", &CControlAPI::GlcdScreenshotCGI, ""}, #endif // boxcontrol - devices {"volume", &CControlAPI::VolumeCGI, "text/plain"}, @@ -2177,6 +2181,23 @@ void CControlAPI::ScreenshotCGI(CyhookHandler *hh) } } #endif +#ifdef ENABLE_GRAPHLCD +void CControlAPI::GlcdScreenshotCGI(CyhookHandler *hh) +{ + std::string filename = "/tmp/glcdscreenshot.png"; + + if(!hh->ParamList["name"].empty()) + filename = hh->ParamList["name"]; + + cGLCD *cglcd = cGLCD::getInstance(); + if (cglcd) { + if (cglcd->dumpBuffer((uint32_t*)cglcd->bitmap->Data(), cGLCD::PNG, filename.c_str())) + hh->SendOk(); + else + hh->SendError(); + } +} +#endif //----------------------------------------------------------------------------- void CControlAPI::ZaptoCGI(CyhookHandler *hh) diff --git a/src/nhttpd/tuxboxapi/controlapi.h b/src/nhttpd/tuxboxapi/controlapi.h index 597fea1bc..534e9afb5 100644 --- a/src/nhttpd/tuxboxapi/controlapi.h +++ b/src/nhttpd/tuxboxapi/controlapi.h @@ -105,6 +105,7 @@ private: void ReloadPluginsCGI(CyhookHandler *hh); void ReloadChannelsCGI(CyhookHandler *hh); void ScreenshotCGI(CyhookHandler *hh); + void GlcdScreenshotCGI(CyhookHandler *hh); void ZaptoCGI(CyhookHandler *hh); void StartPluginCGI(CyhookHandler *hh); void LCDAction(CyhookHandler *hh); diff --git a/src/system/locals.h b/src/system/locals.h index 33f5c7779..6914c93e6 100644 --- a/src/system/locals.h +++ b/src/system/locals.h @@ -913,10 +913,24 @@ typedef enum LOCALE_FSK_TO_12, LOCALE_FSK_TO_16, LOCALE_FSK_TO_7, + LOCALE_GLCD_ALIGN_CENTER, + LOCALE_GLCD_ALIGN_CHANNEL, + LOCALE_GLCD_ALIGN_DURATION, + LOCALE_GLCD_ALIGN_END, + LOCALE_GLCD_ALIGN_EPG, + LOCALE_GLCD_ALIGN_LEFT, + LOCALE_GLCD_ALIGN_NONE, + LOCALE_GLCD_ALIGN_RIGHT, + LOCALE_GLCD_ALIGN_START, + LOCALE_GLCD_ALIGN_TIME, + LOCALE_GLCD_BAR_WIDTH, + LOCALE_GLCD_BAR_X_POSITION, + LOCALE_GLCD_BAR_Y_POSITION, LOCALE_GLCD_BRIGHTNESS, + LOCALE_GLCD_BRIGHTNESS_DIM, + LOCALE_GLCD_BRIGHTNESS_DIM_TIME, + LOCALE_GLCD_BRIGHTNESS_SETTINGS, LOCALE_GLCD_BRIGHTNESS_STANDBY, - LOCALE_GLCD_CLOCK_ANALOG, - LOCALE_GLCD_CLOCK_DIGITAL_HM, LOCALE_GLCD_COLOR_AMBER, LOCALE_GLCD_COLOR_BLACK, LOCALE_GLCD_COLOR_BLUE, @@ -938,25 +952,62 @@ typedef enum LOCALE_GLCD_COLOR_TEAL, LOCALE_GLCD_COLOR_WHITE, LOCALE_GLCD_COLOR_YELLOW, + LOCALE_GLCD_CHANNEL_X_POSITION, + LOCALE_GLCD_CHANNEL_Y_POSITION, + LOCALE_GLCD_DIGITAL_CLOCK_Y_POSITION, LOCALE_GLCD_DISPLAY, + LOCALE_GLCD_DURATION_X_POSITION, + LOCALE_GLCD_DURATION_Y_POSITION, LOCALE_GLCD_ENABLE, + LOCALE_GLCD_END_X_POSITION, + LOCALE_GLCD_END_Y_POSITION, + LOCALE_GLCD_EPG_X_POSITION, + LOCALE_GLCD_EPG_Y_POSITION, LOCALE_GLCD_FONT, + LOCALE_GLCD_FONT_AUTORESIZE, LOCALE_GLCD_HEAD, + LOCALE_GLCD_LOGO_X_POSITION, + LOCALE_GLCD_LOGO_Y_POSITION, LOCALE_GLCD_MIRROR_OSD, LOCALE_GLCD_MIRROR_VIDEO, + LOCALE_GLCD_POSITION_SETTINGS, LOCALE_GLCD_RESTART, LOCALE_GLCD_SCROLL_SPEED, LOCALE_GLCD_SELECT_BAR, LOCALE_GLCD_SELECT_BG, LOCALE_GLCD_SELECT_FG, + LOCALE_GLCD_SHOW_DURATION, + LOCALE_GLCD_SHOW_END, LOCALE_GLCD_SHOW_LOGO, + LOCALE_GLCD_SHOW_PROGRESSBAR, + LOCALE_GLCD_SHOW_START, + LOCALE_GLCD_SHOW_TIME, + LOCALE_GLCD_SHOW_WEATHER, + LOCALE_GLCD_SIMPLE_CLOCK_Y_POSITION, LOCALE_GLCD_SIZE_BAR, LOCALE_GLCD_SIZE_CHANNEL, + LOCALE_GLCD_SIZE_DURATION, + LOCALE_GLCD_SIZE_END, LOCALE_GLCD_SIZE_EPG, LOCALE_GLCD_SIZE_LOGO, + LOCALE_GLCD_SIZE_SIMPLE_CLOCK, + LOCALE_GLCD_SIZE_START, LOCALE_GLCD_SIZE_TIME, LOCALE_GLCD_SIZE_TIME_STANDBY, + LOCALE_GLCD_THEME, + LOCALE_GLCD_THEME_POSITION_SETTINGS, + LOCALE_GLCD_THEME_SETTINGS, + LOCALE_GLCD_STANDBY_ANALOG_CLOCK, + LOCALE_GLCD_STANDBY_DIGITAL_CLOCK, + LOCALE_GLCD_STANDBY_LCD_CLOCK, + LOCALE_GLCD_STANDBY_LED_CLOCK, + LOCALE_GLCD_STANDBY_SETTINGS, + LOCALE_GLCD_STANDBY_WEATHER, + LOCALE_GLCD_START_X_POSITION, + LOCALE_GLCD_START_Y_POSITION, LOCALE_GLCD_TIME_IN_STANDBY, + LOCALE_GLCD_TIME_X_POSITION, + LOCALE_GLCD_TIME_Y_POSITION, LOCALE_GLCD_VOLUME, LOCALE_HDD_10MIN, LOCALE_HDD_1MIN, @@ -1844,6 +1895,7 @@ typedef enum LOCALE_MENU_HINT_VOLUME_POS, LOCALE_MENU_HINT_VOLUME_SIZE, LOCALE_MENU_HINT_WEATHER_API_KEY, + LOCALE_MENU_HINT_WEATHER_COUNTRY, LOCALE_MENU_HINT_WEATHER_ENABLED, LOCALE_MENU_HINT_WEATHER_LOCATION, LOCALE_MENU_HINT_WEBRADIO_SETUP, @@ -2958,6 +3010,9 @@ typedef enum LOCALE_VIDEOMENU_ZAPPINGMODE_MUTE, LOCALE_VIDEOMENU_ZAPPINGMODE_HOLD, LOCALE_WEATHER_API_KEY, + LOCALE_WEATHER_COUNTRY, + LOCALE_WEATHER_COUNTRY_DEUTSCHLAND, + LOCALE_WEATHER_COUNTRY_NORWAY, LOCALE_WEATHER_ENABLED, LOCALE_WEATHER_LOCATION, LOCALE_WEBRADIO_HEAD, diff --git a/src/system/locals_intern.h b/src/system/locals_intern.h index b56a704dd..b3066f5c0 100644 --- a/src/system/locals_intern.h +++ b/src/system/locals_intern.h @@ -913,10 +913,24 @@ const char * locale_real_names[] = "fsk.to_12", "fsk.to_16", "fsk.to_7", + "glcd.align_center", + "glcd.align_channel", + "glcd.align_duration", + "glcd.align_end", + "glcd.align_epg", + "glcd.align_left", + "glcd.align_none", + "glcd.align_right", + "glcd.align_start", + "glcd.align_time", + "glcd.bar_width", + "glcd.bar_x_position", + "glcd.bar_y_position", "glcd.brightness", + "glcd.brightness_dim", + "glcd.brightness_dim_time", + "glcd.brightness_settings", "glcd.brightness_standby", - "glcd.clock.analog", - "glcd.clock.digital_hm", "glcd.color.amber", "glcd.color.black", "glcd.color.blue", @@ -938,25 +952,62 @@ const char * locale_real_names[] = "glcd.color.teal", "glcd.color.white", "glcd.color.yellow", + "glcd.channel_x_position", + "glcd.channel_y_position", + "glcd.digital_clock_y_position", "glcd.display", + "glcd.duration_x_position", + "glcd.duration_y_position", "glcd.enable", + "glcd.end_x_position", + "glcd.end_y_position", + "glcd.epg_x_position", + "glcd.epg_y_position", "glcd.font", + "glcd.font_autoresize", "glcd.head", + "glcd.logo_x_position", + "glcd.logo_y_position", "glcd.mirror_osd", "glcd.mirror_video", + "glcd.position_settings", "glcd.restart", "glcd.scroll_speed", "glcd.select.bar", "glcd.select.bg", "glcd.select.fg", + "glcd.show_duration", + "glcd.show_end", "glcd.show_logo", + "glcd.show_progressbar", + "glcd.show_start", + "glcd.show_time", + "glcd.show_weather", + "glcd.simple_clock_y_position", "glcd.size_bar", "glcd.size_channel", + "glcd.size_duration", + "glcd.size_end", "glcd.size_epg", "glcd.size_logo", + "glcd.size_simple_clock", + "glcd.size_start", "glcd.size_time", "glcd.size_time_standby", + "glcd.theme", + "glcd.theme_position_settings", + "glcd.theme_settings", + "glcd.standby_analog_clock", + "glcd.standby_digital_clock", + "glcd.standby_lcd_clock", + "glcd.standby_led_clock", + "glcd.standby_settings", + "glcd.standby_weather", + "glcd.start_x_position", + "glcd.start_y_position", "glcd.time_in_standby", + "glcd.time_x_position", + "glcd.time_y_position", "glcd.volume", "hdd_10min", "hdd_1min", @@ -1844,6 +1895,7 @@ const char * locale_real_names[] = "menu.hint_volume_pos", "menu.hint_volume_size", "menu.hint_weather_api_key", + "menu.hint_weather_country", "menu.hint_weather_enabled", "menu.hint_weather_location", "menu.hint_webradio_setup", @@ -2958,6 +3010,9 @@ const char * locale_real_names[] = "videomenu.zappingmode_mute", "videomenu.zappingmode_hold", "weather.api_key", + "weather.country", + "weather.country_deutschland", + "weather.country_norway", "weather.enabled", "weather.location", "webradio.head", diff --git a/src/system/settings.h b/src/system/settings.h index dfc8f3e5c..6c6e33755 100644 --- a/src/system/settings.h +++ b/src/system/settings.h @@ -183,6 +183,108 @@ struct timer_remotebox_item bool online; }; +#if BOXMODEL_VUSOLO4K || BOXMODEL_VUDUO4K || BOXMODEL_VUULTIMO4K || BOXMODEL_VUUNO4KSE || BOXMODEL_VUUNO4K +#define GLCD_DEFAULT_BRIGHTNESS 7 +#define GLCD_DEFAULT_BRIGHTNESS_STANDBY 1 +#define GLCD_DEFAULT_BRIGHTNESS_DIM 3 +#define GLCD_DEFAULT_BRIGHTNESS_DIM_TIME "10" +#else +#define GLCD_DEFAULT_BRIGHTNESS 70 +#define GLCD_DEFAULT_BRIGHTNESS_STANDBY 10 +#define GLCD_DEFAULT_BRIGHTNESS_DIM 30 +#define GLCD_DEFAULT_BRIGHTNESS_DIM_TIME "30" +#endif + +struct SNeutrinoGlcdTheme +{ + unsigned char glcd_color_fg_red; + unsigned char glcd_color_fg_green; + unsigned char glcd_color_fg_blue; + unsigned char glcd_color_bg_red; + unsigned char glcd_color_bg_green; + unsigned char glcd_color_bg_blue; + unsigned char glcd_color_bar_red; + unsigned char glcd_color_bar_green; + unsigned char glcd_color_bar_blue; + + std::string glcd_font; + std::string glcd_background; + + int glcd_show_progressbar; + int glcd_show_duration; + int glcd_show_start; + int glcd_show_end; + int glcd_show_time; + int glcd_show_weather; + + int glcd_align_channel; + int glcd_align_epg; + int glcd_align_duration; + int glcd_align_start; + int glcd_align_end; + int glcd_align_time; + + int glcd_percent_channel; + int glcd_channel_x_position; + int glcd_channel_y_position; + + int glcd_percent_epg; + int glcd_epg_x_position; + int glcd_epg_y_position; + + int glcd_percent_duration; + int glcd_duration_x_position; + int glcd_duration_y_position; + + int glcd_percent_start; + int glcd_start_x_position; + int glcd_start_y_position; + + int glcd_percent_end; + int glcd_end_x_position; + int glcd_end_y_position; + + int glcd_percent_time; + int glcd_time_x_position; + int glcd_time_y_position; + + int glcd_percent_bar; + int glcd_bar_x_position; + int glcd_bar_y_position; + int glcd_bar_width; + + int glcd_percent_logo; + int glcd_logo_x_position; + int glcd_logo_y_position; + + int glcd_percent_smalltext; + int glcd_smalltext_y_position; + + int glcd_rec_icon_x_position; + int glcd_mute_icon_x_position; + int glcd_ts_icon_x_position; + int glcd_timer_icon_x_position; + int glcd_ecm_icon_x_position; + int glcd_dd_icon_x_position; + int glcd_txt_icon_x_position; + int glcd_cam_icon_x_position; + + int glcd_standby_weather; + int glcd_digital_clock_y_position; + int glcd_size_simple_clock; + int glcd_simple_clock_y_position; + + int glcd_weather_x_position_current; + int glcd_weather_x_position_next; + int glcd_weather_y_position; + + int glcd_weather_x_position_current_standby; + int glcd_weather_x_position_next_standby; + int glcd_weather_y_position_standby; + + int glcd_position_settings; +}; + struct SNeutrinoSettings { std::string version_pseudo; @@ -485,6 +587,8 @@ struct SNeutrinoSettings //theme/color options SNeutrinoTheme theme; std::string theme_name; + SNeutrinoGlcdTheme glcd_theme; + std::string glcd_theme_name; bool osd_colorsettings_advanced_mode; //network @@ -810,22 +914,18 @@ struct SNeutrinoSettings #ifdef ENABLE_GRAPHLCD // graphlcd int glcd_enable; - uint32_t glcd_color_fg; - uint32_t glcd_color_bg; - uint32_t glcd_color_bar; - std::string glcd_font; - int glcd_percent_channel; - int glcd_percent_epg; - int glcd_percent_bar; - int glcd_percent_time; - int glcd_percent_time_standby; - int glcd_percent_logo; + + int glcd_time_in_standby; + int glcd_standby_weather; + int glcd_mirror_osd; int glcd_mirror_video; - int glcd_time_in_standby; + int glcd_show_logo; int glcd_brightness; int glcd_brightness_standby; + int glcd_brightness_dim; + std::string glcd_brightness_dim_time; int glcd_scroll_speed; int glcd_selected_config; #endif @@ -904,6 +1004,7 @@ struct SNeutrinoSettings //online services std::string weather_api_key; int weather_enabled; + int weather_country; std::string weather_location; std::string weather_city; std::string youtube_dev_id; diff --git a/src/timerd/timermanager.cpp b/src/timerd/timermanager.cpp index e94ccdcbb..f9c493b62 100644 --- a/src/timerd/timermanager.cpp +++ b/src/timerd/timermanager.cpp @@ -44,6 +44,8 @@ #include "timermanager.h" #include +#include + extern bool timeset; time_t timer_minutes; bool timer_is_rec; @@ -93,6 +95,8 @@ void* CTimerManager::timerThread(void *arg) CTimerManager *timerManager = (CTimerManager*) arg; + bool setTimerIcon = false; + int sleeptime=(timerd_debug)?10:20; while(1) { @@ -126,6 +130,12 @@ void* CTimerManager::timerThread(void *arg) CTimerEventMap::iterator pos = timerManager->events.begin(); for(;pos != timerManager->events.end();++pos) { +#ifdef ENABLE_GRAPHLCD + if (!setTimerIcon) { + cGLCD::lockIcon(cGLCD::TIMER); + setTimerIcon = true; + } +#endif event = pos->second; dprintf("checking event: %03d\n",event->eventID); if (timerd_debug) @@ -149,6 +159,12 @@ void* CTimerManager::timerThread(void *arg) if(event->stopTime == 0) // if event needs no stop event event->setState(CTimerd::TIMERSTATE_HASFINISHED); timerManager->m_saveEvents = true; +#ifdef ENABLE_GRAPHLCD + if (setTimerIcon) { + cGLCD::unlockIcon(cGLCD::TIMER); + setTimerIcon = false; + } +#endif } if(event->stopTime > 0 && event->eventState == CTimerd::TIMERSTATE_ISRUNNING ) // check if stopevent is wanted @@ -223,6 +239,9 @@ CTimerEvent* CTimerManager::getNextEvent() //------------------------------------------------------------ int CTimerManager::addEvent(CTimerEvent* evt, bool save) { +#ifdef ENABLE_GRAPHLCD + cGLCD::lockIcon(cGLCD::TIMER); +#endif pthread_mutex_lock(&tm_eventsMutex); eventID++; // increase unique event id evt->eventID = eventID;