summaryrefslogtreecommitdiff
path: root/firmware/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers')
-rw-r--r--firmware/drivers/lcd-16bit.c347
-rw-r--r--firmware/drivers/lcd-1bit-vert.c224
-rw-r--r--firmware/drivers/lcd-2bit-horz.c221
-rw-r--r--firmware/drivers/lcd-2bit-vert.c226
-rw-r--r--firmware/drivers/lcd-2bit-vi.c225
-rw-r--r--firmware/drivers/lcd-bitmap-common.c329
6 files changed, 336 insertions, 1236 deletions
diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c
index 882bfa0854..7238d7a923 100644
--- a/firmware/drivers/lcd-16bit.c
+++ b/firmware/drivers/lcd-16bit.c
@@ -638,70 +638,6 @@ void lcd_fillrect(int x, int y, int width, int height)
638 while (dst < dst_end); 638 while (dst < dst_end);
639} 639}
640 640
641/* Fill a rectangle with a gradient */
642static void lcd_gradient_rect(int x1, int x2, int y, int h)
643{
644 int old_pattern = current_vp->fg_pattern;
645
646 if (h == 0) return;
647
648 int h_r = RGB_UNPACK_RED(current_vp->lss_pattern) << 16;
649 int h_b = RGB_UNPACK_BLUE(current_vp->lss_pattern) << 16;
650 int h_g = RGB_UNPACK_GREEN(current_vp->lss_pattern) << 16;
651 int rstep = (h_r - ((signed)RGB_UNPACK_RED(current_vp->lse_pattern) << 16)) / h;
652 int gstep = (h_g - ((signed)RGB_UNPACK_GREEN(current_vp->lse_pattern) << 16)) / h;
653 int bstep = (h_b - ((signed)RGB_UNPACK_BLUE(current_vp->lse_pattern) << 16)) / h;
654 int count;
655
656 current_vp->fg_pattern = current_vp->lss_pattern;
657 for(count = 0; count < h; count++) {
658 lcd_hline(x1, x2, y + count);
659 h_r -= rstep;
660 h_g -= gstep;
661 h_b -= bstep;
662 current_vp->fg_pattern = LCD_RGBPACK(h_r >> 16, h_g >> 16, h_b >> 16);
663 }
664
665 current_vp->fg_pattern = old_pattern;
666}
667
668#define H_COLOR(lss, lse, cur_line, max_line) \
669 (((lse) - (lss)) * (cur_line) / (max_line) + (lss))
670
671/* Fill a rectangle with a gradient for scrolling line. To draw a gradient that
672 covers several lines, we need to know how many lines will be covered
673 (the num_lines arg), and which one is the current line within the selection
674 (the cur_line arg). */
675static void lcd_gradient_rect_scroll(int x1, int x2, int y, int h,
676 unsigned char num_lines, unsigned char cur_line)
677{
678 if (h == 0 || num_lines == 0) return;
679
680 unsigned tmp_lss = current_vp->lss_pattern;
681 unsigned tmp_lse = current_vp->lse_pattern;
682 int lss_r = (signed)RGB_UNPACK_RED(current_vp->lss_pattern);
683 int lss_b = (signed)RGB_UNPACK_BLUE(current_vp->lss_pattern);
684 int lss_g = (signed)RGB_UNPACK_GREEN(current_vp->lss_pattern);
685 int lse_r = (signed)RGB_UNPACK_RED(current_vp->lse_pattern);
686 int lse_b = (signed)RGB_UNPACK_BLUE(current_vp->lse_pattern);
687 int lse_g = (signed)RGB_UNPACK_GREEN(current_vp->lse_pattern);
688
689 int h_r = H_COLOR(lss_r, lse_r, cur_line, num_lines);
690 int h_g = H_COLOR(lss_g, lse_g, cur_line, num_lines);
691 int h_b = H_COLOR(lss_b, lse_b, cur_line, num_lines);
692 lcd_set_selector_start(LCD_RGBPACK(h_r, h_g, h_b));
693
694 int l_r = H_COLOR(lss_r, lse_r, cur_line+1, num_lines);
695 int l_g = H_COLOR(lss_g, lse_g, cur_line+1, num_lines);
696 int l_b = H_COLOR(lss_b, lse_b, cur_line+1, num_lines);
697 lcd_set_selector_end(LCD_RGBPACK(l_r, l_g, l_b));
698
699 lcd_gradient_rect(x1, x2, y, h);
700
701 current_vp->lss_pattern = tmp_lss;
702 current_vp->lse_pattern = tmp_lse;
703}
704
705/* About Rockbox' internal monochrome bitmap format: 641/* About Rockbox' internal monochrome bitmap format:
706 * 642 *
707 * A bitmap contains one bit for every pixel that defines if that pixel is 643 * A bitmap contains one bit for every pixel that defines if that pixel is
@@ -977,285 +913,4 @@ void lcd_bitmap_transparent(const fb_data *src, int x, int y,
977 lcd_bitmap_transparent_part(src, 0, 0, width, x, y, width, height); 913 lcd_bitmap_transparent_part(src, 0, 0, width, x, y, width, height);
978} 914}
979 915
980/* put a string at a given pixel position, skipping first ofs pixel columns */ 916#include "lcd-bitmap-common.c"
981static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
982{
983 unsigned short ch;
984 unsigned short *ucs;
985 struct font* pf = font_get(current_vp->font);
986
987 ucs = bidi_l2v(str, 1);
988
989 while ((ch = *ucs++) != 0 && x < current_vp->width)
990 {
991 int width;
992 const unsigned char *bits;
993
994 /* get proportional width and glyph bits */
995 width = font_get_width(pf,ch);
996
997 if (ofs > width)
998 {
999 ofs -= width;
1000 continue;
1001 }
1002
1003 bits = font_get_bits(pf, ch);
1004
1005 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height);
1006
1007 x += width - ofs;
1008 ofs = 0;
1009 }
1010}
1011
1012/* put a string at a given pixel position */
1013void lcd_putsxy(int x, int y, const unsigned char *str)
1014{
1015 lcd_putsxyofs(x, y, 0, str);
1016}
1017
1018/*** line oriented text output ***/
1019
1020/* put a string at a given char position */
1021void lcd_puts(int x, int y, const unsigned char *str)
1022{
1023 lcd_puts_style_offset(x, y, str, STYLE_DEFAULT, 0);
1024}
1025
1026void lcd_puts_style(int x, int y, const unsigned char *str, int style)
1027{
1028 lcd_puts_style_offset(x, y, str, style, 0);
1029}
1030
1031void lcd_puts_offset(int x, int y, const unsigned char *str, int offset)
1032{
1033 lcd_puts_style_offset(x, y, str, STYLE_DEFAULT, offset);
1034}
1035
1036/* put a string at a given char position, style, and pixel position,
1037 * skipping first offset pixel columns */
1038void lcd_puts_style_offset(int x, int y, const unsigned char *str, int style,
1039 int offset)
1040{
1041 int xpos,ypos,w,h,xrect;
1042 int lastmode = current_vp->drawmode;
1043 int oldfgcolor = current_vp->fg_pattern;
1044 int oldbgcolor = current_vp->bg_pattern;
1045
1046 /* make sure scrolling is turned off on the line we are updating */
1047 lcd_scroll_stop_line(current_vp, y);
1048
1049 if(!str || !str[0])
1050 return;
1051
1052 lcd_getstringsize(str, &w, &h);
1053 xpos = x*w / utf8length(str);
1054 ypos = y*h;
1055 current_vp->drawmode = (style & STYLE_INVERT) ?
1056 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
1057 if (style & STYLE_COLORED) {
1058 if (current_vp->drawmode == DRMODE_SOLID)
1059 current_vp->fg_pattern = style & STYLE_COLOR_MASK;
1060 else
1061 current_vp->bg_pattern = style & STYLE_COLOR_MASK;
1062 }
1063 current_vp->drawmode ^= DRMODE_INVERSEVID;
1064 xrect = xpos + MAX(w - offset, 0);
1065
1066 if (style & STYLE_GRADIENT) {
1067 current_vp->drawmode = DRMODE_FG;
1068 if (CURLN_UNPACK(style) == 0)
1069 lcd_gradient_rect(xpos, current_vp->width, ypos, h*NUMLN_UNPACK(style));
1070 current_vp->fg_pattern = current_vp->lst_pattern;
1071 }
1072 else if (style & STYLE_COLORBAR) {
1073 current_vp->drawmode = DRMODE_FG;
1074 current_vp->fg_pattern = current_vp->lss_pattern;
1075 lcd_fillrect(xpos, ypos, current_vp->width - xpos, h);
1076 current_vp->fg_pattern = current_vp->lst_pattern;
1077 }
1078 else {
1079 lcd_fillrect(xrect, ypos, current_vp->width - xrect, h);
1080 current_vp->drawmode = (style & STYLE_INVERT) ?
1081 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
1082 }
1083 lcd_putsxyofs(xpos, ypos, offset, str);
1084 current_vp->drawmode = lastmode;
1085 current_vp->fg_pattern = oldfgcolor;
1086 current_vp->bg_pattern = oldbgcolor;
1087}
1088
1089/*** scrolling ***/
1090void lcd_puts_scroll(int x, int y, const unsigned char *string)
1091{
1092 lcd_puts_scroll_style(x, y, string, STYLE_DEFAULT);
1093}
1094
1095void lcd_puts_scroll_style(int x, int y, const unsigned char *string, int style)
1096{
1097 lcd_puts_scroll_style_offset(x, y, string, style, 0);
1098}
1099
1100void lcd_puts_scroll_offset(int x, int y, const unsigned char *string, int offset)
1101{
1102 lcd_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset);
1103}
1104
1105/* Initialise a scrolling line at (x,y) in current viewport */
1106
1107void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
1108 int style, int offset)
1109{
1110 struct scrollinfo* s;
1111 int w, h;
1112
1113 if ((unsigned)y >= (unsigned)current_vp->height)
1114 return;
1115
1116 /* remove any previously scrolling line at the same location */
1117 lcd_scroll_stop_line(current_vp, y);
1118
1119 if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return;
1120
1121 s = &lcd_scroll_info.scroll[lcd_scroll_info.lines];
1122
1123 s->start_tick = current_tick + lcd_scroll_info.delay;
1124 s->style = style;
1125 lcd_puts_style_offset(x,y,string,style,offset);
1126
1127 lcd_getstringsize(string, &w, &h);
1128
1129 if (current_vp->width - x * 8 < w) {
1130 /* prepare scroll line */
1131 char *end;
1132
1133 memset(s->line, 0, sizeof s->line);
1134 strcpy(s->line, string);
1135
1136 /* get width */
1137 s->width = lcd_getstringsize(s->line, &w, &h);
1138
1139 /* scroll bidirectional or forward only depending on the string
1140 width */
1141 if ( lcd_scroll_info.bidir_limit ) {
1142 s->bidir = s->width < (current_vp->width) *
1143 (100 + lcd_scroll_info.bidir_limit) / 100;
1144 }
1145 else
1146 s->bidir = false;
1147
1148 if (!s->bidir) { /* add spaces if scrolling in the round */
1149 strcat(s->line, " ");
1150 /* get new width incl. spaces */
1151 s->width = lcd_getstringsize(s->line, &w, &h);
1152 }
1153
1154 end = strchr(s->line, '\0');
1155 strlcpy(end, string, current_vp->width/2);
1156
1157 s->vp = current_vp;
1158 s->y = y;
1159 s->len = utf8length(string);
1160 s->offset = offset;
1161 s->startx = x * s->width / s->len;
1162 s->backward = false;
1163 lcd_scroll_info.lines++;
1164 }
1165}
1166
1167void lcd_scroll_fn(void)
1168{
1169 struct font* pf;
1170 struct scrollinfo* s;
1171 int index;
1172 int xpos, ypos;
1173 int lastmode;
1174 unsigned old_fgcolor;
1175 unsigned old_bgcolor;
1176 struct viewport* old_vp = current_vp;
1177
1178 for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
1179 s = &lcd_scroll_info.scroll[index];
1180
1181 /* check pause */
1182 if (TIME_BEFORE(current_tick, s->start_tick))
1183 continue;
1184
1185 lcd_set_viewport(s->vp);
1186 old_fgcolor = current_vp->fg_pattern;
1187 old_bgcolor = current_vp->bg_pattern;
1188
1189 if (s->style&STYLE_COLORED) {
1190 if (s->style&STYLE_MODE_MASK) {
1191 current_vp->fg_pattern = old_fgcolor;
1192 current_vp->bg_pattern = s->style&STYLE_COLOR_MASK;
1193 }
1194 else {
1195 current_vp->fg_pattern = s->style&STYLE_COLOR_MASK;
1196 current_vp->bg_pattern = old_bgcolor;
1197 }
1198 }
1199
1200 if (s->backward)
1201 s->offset -= lcd_scroll_info.step;
1202 else
1203 s->offset += lcd_scroll_info.step;
1204
1205 pf = font_get(current_vp->font);
1206 xpos = s->startx;
1207 ypos = s->y * pf->height;
1208
1209 if (s->bidir) { /* scroll bidirectional */
1210 if (s->offset <= 0) {
1211 /* at beginning of line */
1212 s->offset = 0;
1213 s->backward = false;
1214 s->start_tick = current_tick + lcd_scroll_info.delay * 2;
1215 }
1216 if (s->offset >= s->width - (current_vp->width - xpos)) {
1217 /* at end of line */
1218 s->offset = s->width - (current_vp->width - xpos);
1219 s->backward = true;
1220 s->start_tick = current_tick + lcd_scroll_info.delay * 2;
1221 }
1222 }
1223 else {
1224 /* scroll forward the whole time */
1225 if (s->offset >= s->width)
1226 s->offset %= s->width;
1227 }
1228
1229 lastmode = current_vp->drawmode;
1230 switch (s->style&STYLE_MODE_MASK) {
1231 case STYLE_INVERT:
1232 current_vp->drawmode = DRMODE_SOLID|DRMODE_INVERSEVID;
1233 break;
1234 case STYLE_COLORBAR:
1235 /* Solid colour line selector */
1236 current_vp->drawmode = DRMODE_FG;
1237 current_vp->fg_pattern = current_vp->lss_pattern;
1238 lcd_fillrect(xpos, ypos, current_vp->width - xpos, pf->height);
1239 current_vp->fg_pattern = current_vp->lst_pattern;
1240 break;
1241 case STYLE_GRADIENT:
1242 /* Gradient line selector */
1243 current_vp->drawmode = DRMODE_FG;
1244 lcd_gradient_rect_scroll(xpos, current_vp->width, ypos, (signed)pf->height,
1245 NUMLN_UNPACK(s->style),
1246 CURLN_UNPACK(s->style));
1247 current_vp->fg_pattern = current_vp->lst_pattern;
1248 break;
1249 default:
1250 current_vp->drawmode = DRMODE_SOLID;
1251 break;
1252 }
1253 lcd_putsxyofs(xpos, ypos, s->offset, s->line);
1254 current_vp->drawmode = lastmode;
1255 current_vp->fg_pattern = old_fgcolor;
1256 current_vp->bg_pattern = old_bgcolor;
1257 lcd_update_viewport_rect(xpos, ypos, current_vp->width - xpos, pf->height);
1258 }
1259
1260 lcd_set_viewport(old_vp);
1261}
diff --git a/firmware/drivers/lcd-1bit-vert.c b/firmware/drivers/lcd-1bit-vert.c
index f11fd6fdf9..db8cc6771b 100644
--- a/firmware/drivers/lcd-1bit-vert.c
+++ b/firmware/drivers/lcd-1bit-vert.c
@@ -692,226 +692,4 @@ void LCDFN(bitmap)(const unsigned char *src, int x, int y, int width,
692 LCDFN(bitmap_part)(src, 0, 0, width, x, y, width, height); 692 LCDFN(bitmap_part)(src, 0, 0, width, x, y, width, height);
693} 693}
694 694
695/* put a string at a given pixel position, skipping first ofs pixel columns */ 695#include "lcd-bitmap-common.c"
696static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str)
697{
698 unsigned short ch;
699 unsigned short *ucs;
700 struct font* pf = font_get(current_vp->font);
701
702 ucs = bidi_l2v(str, 1);
703
704 while ((ch = *ucs++) != 0 && x < current_vp->width)
705 {
706 int width;
707 const unsigned char *bits;
708
709 /* get proportional width and glyph bits */
710 width = font_get_width(pf, ch);
711
712 if (ofs > width)
713 {
714 ofs -= width;
715 continue;
716 }
717
718 bits = font_get_bits(pf, ch);
719
720 LCDFN(mono_bitmap_part)(bits, ofs, 0, width, x, y, width - ofs,
721 pf->height);
722
723 x += width - ofs;
724 ofs = 0;
725 }
726}
727/* put a string at a given pixel position */
728void LCDFN(putsxy)(int x, int y, const unsigned char *str)
729{
730 LCDFN(putsxyofs)(x, y, 0, str);
731}
732
733/*** Line oriented text output ***/
734
735/* put a string at a given char position */
736void LCDFN(puts)(int x, int y, const unsigned char *str)
737{
738 LCDFN(puts_style_offset)(x, y, str, STYLE_DEFAULT, 0);
739}
740
741void LCDFN(puts_style)(int x, int y, const unsigned char *str, int style)
742{
743 LCDFN(puts_style_offset)(x, y, str, style, 0);
744}
745
746void LCDFN(puts_offset)(int x, int y, const unsigned char *str, int offset)
747{
748 LCDFN(puts_style_offset)(x, y, str, STYLE_DEFAULT, offset);
749}
750
751/* put a string at a given char position, style, and pixel position,
752 * skipping first offset pixel columns */
753void LCDFN(puts_style_offset)(int x, int y, const unsigned char *str,
754 int style, int offset)
755{
756 int xpos,ypos,w,h,xrect;
757 int lastmode = current_vp->drawmode;
758
759 /* make sure scrolling is turned off on the line we are updating */
760 LCDFN(scroll_stop_line)(current_vp, y);
761
762 if(!str || !str[0])
763 return;
764
765 LCDFN(getstringsize)(str, &w, &h);
766 xpos = x*w / utf8length(str);
767 ypos = y*h;
768 current_vp->drawmode = (style & STYLE_INVERT) ?
769 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
770 LCDFN(putsxyofs)(xpos, ypos, offset, str);
771 current_vp->drawmode ^= DRMODE_INVERSEVID;
772 xrect = xpos + MAX(w - offset, 0);
773 LCDFN(fillrect)(xrect, ypos, current_vp->width - xrect, h);
774 current_vp->drawmode = lastmode;
775}
776
777/*** scrolling ***/
778
779void LCDFN(puts_scroll)(int x, int y, const unsigned char *string)
780{
781 LCDFN(puts_scroll_style)(x, y, string, STYLE_DEFAULT);
782}
783
784void LCDFN(puts_scroll_style)(int x, int y, const unsigned char *string,
785 int style)
786{
787 LCDFN(puts_scroll_style_offset)(x, y, string, style, 0);
788}
789
790void LCDFN(puts_scroll_offset)(int x, int y, const unsigned char *string,
791 int offset)
792{
793 LCDFN(puts_scroll_style_offset)(x, y, string, STYLE_DEFAULT, offset);
794}
795
796void LCDFN(puts_scroll_style_offset)(int x, int y, const unsigned char *string,
797 int style, int offset)
798{
799 struct scrollinfo* s;
800 int w, h;
801
802 if ((unsigned)y >= (unsigned)current_vp->height)
803 return;
804
805 /* remove any previously scrolling line at the same location */
806 LCDFN(scroll_stop_line)(current_vp, y);
807
808 if (LCDFN(scroll_info.lines) >= LCDM(SCROLLABLE_LINES)) return;
809
810 s = &LCDFN(scroll_info).scroll[LCDFN(scroll_info).lines];
811
812 s->start_tick = current_tick + LCDFN(scroll_info).delay;
813 s->style = style;
814 if (style & STYLE_INVERT) {
815 LCDFN(puts_style_offset)(x,y,string,STYLE_INVERT,offset);
816 }
817 else
818 LCDFN(puts_offset)(x,y,string,offset);
819
820 LCDFN(getstringsize)(string, &w, &h);
821
822 if (current_vp->width - x * 8 < w) {
823 /* prepare scroll line */
824 char *end;
825
826 memset(s->line, 0, sizeof s->line);
827 strcpy(s->line, string);
828
829 /* get width */
830 s->width = LCDFN(getstringsize)(s->line, &w, &h);
831
832 /* scroll bidirectional or forward only depending on the string
833 width */
834 if ( LCDFN(scroll_info).bidir_limit ) {
835 s->bidir = s->width < (current_vp->width) *
836 (100 + LCDFN(scroll_info).bidir_limit) / 100;
837 }
838 else
839 s->bidir = false;
840
841 if (!s->bidir) { /* add spaces if scrolling in the round */
842 strcat(s->line, " ");
843 /* get new width incl. spaces */
844 s->width = LCDFN(getstringsize)(s->line, &w, &h);
845 }
846
847 end = strchr(s->line, '\0');
848 strlcpy(end, string, current_vp->width/2);
849
850 s->vp = current_vp;
851 s->y = y;
852 s->len = utf8length(string);
853 s->offset = offset;
854 s->startx = x * s->width / s->len;
855 s->backward = false;
856
857 LCDFN(scroll_info).lines++;
858 }
859}
860
861void LCDFN(scroll_fn)(void)
862{
863 struct font* pf;
864 struct scrollinfo* s;
865 int index;
866 int xpos, ypos;
867 int lastmode;
868 struct viewport* old_vp = current_vp;
869
870 for ( index = 0; index < LCDFN(scroll_info).lines; index++ ) {
871 s = &LCDFN(scroll_info).scroll[index];
872
873 /* check pause */
874 if (TIME_BEFORE(current_tick, s->start_tick))
875 continue;
876
877 LCDFN(set_viewport)(s->vp);
878
879 if (s->backward)
880 s->offset -= LCDFN(scroll_info).step;
881 else
882 s->offset += LCDFN(scroll_info).step;
883
884 pf = font_get(current_vp->font);
885 xpos = s->startx;
886 ypos = s->y * pf->height;
887
888 if (s->bidir) { /* scroll bidirectional */
889 if (s->offset <= 0) {
890 /* at beginning of line */
891 s->offset = 0;
892 s->backward = false;
893 s->start_tick = current_tick + LCDFN(scroll_info).delay * 2;
894 }
895 if (s->offset >= s->width - (current_vp->width - xpos)) {
896 /* at end of line */
897 s->offset = s->width - (current_vp->width - xpos);
898 s->backward = true;
899 s->start_tick = current_tick + LCDFN(scroll_info).delay * 2;
900 }
901 }
902 else {
903 /* scroll forward the whole time */
904 if (s->offset >= s->width)
905 s->offset %= s->width;
906 }
907
908 lastmode = current_vp->drawmode;
909 current_vp->drawmode = (s->style&STYLE_INVERT) ?
910 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
911 LCDFN(putsxyofs)(xpos, ypos, s->offset, s->line);
912 current_vp->drawmode = lastmode;
913 LCDFN(update_viewport_rect)(xpos, ypos, current_vp->width - xpos, pf->height);
914 }
915
916 LCDFN(set_viewport)(old_vp);
917}
diff --git a/firmware/drivers/lcd-2bit-horz.c b/firmware/drivers/lcd-2bit-horz.c
index 463eece569..bb540a9ae1 100644
--- a/firmware/drivers/lcd-2bit-horz.c
+++ b/firmware/drivers/lcd-2bit-horz.c
@@ -956,223 +956,4 @@ void lcd_bitmap(const unsigned char *src, int x, int y, int width, int height)
956 lcd_bitmap_part(src, 0, 0, width, x, y, width, height); 956 lcd_bitmap_part(src, 0, 0, width, x, y, width, height);
957} 957}
958 958
959/* put a string at a given pixel position, skipping first ofs pixel columns */ 959#include "lcd-bitmap-common.c"
960static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
961{
962 unsigned short ch;
963 unsigned short *ucs;
964 struct font* pf = font_get(current_vp->font);
965
966 ucs = bidi_l2v(str, 1);
967
968 while ((ch = *ucs++) != 0 && x < current_vp->width)
969 {
970 int width;
971 const unsigned char *bits;
972
973 /* get proportional width and glyph bits */
974 width = font_get_width(pf,ch);
975
976 if (ofs > width)
977 {
978 ofs -= width;
979 continue;
980 }
981
982 bits = font_get_bits(pf, ch);
983
984 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs,
985 pf->height);
986
987 x += width - ofs;
988 ofs = 0;
989 }
990}
991
992/* put a string at a given pixel position */
993void lcd_putsxy(int x, int y, const unsigned char *str)
994{
995 lcd_putsxyofs(x, y, 0, str);
996}
997
998/*** line oriented text output ***/
999
1000/* put a string at a given char position */
1001void lcd_puts(int x, int y, const unsigned char *str)
1002{
1003 lcd_puts_style_offset(x, y, str, STYLE_DEFAULT, 0);
1004}
1005
1006void lcd_puts_style(int x, int y, const unsigned char *str, int style)
1007{
1008 lcd_puts_style_offset(x, y, str, style, 0);
1009}
1010
1011void lcd_puts_offset(int x, int y, const unsigned char *str, int offset)
1012{
1013 lcd_puts_style_offset(x, y, str, STYLE_DEFAULT, offset);
1014}
1015
1016/* put a string at a given char position, style, and pixel position,
1017 * skipping first offset pixel columns */
1018void lcd_puts_style_offset(int x, int y, const unsigned char *str,
1019 int style, int offset)
1020{
1021 int xpos,ypos,w,h,xrect;
1022 int lastmode = current_vp->drawmode;
1023
1024 /* make sure scrolling is turned off on the line we are updating */
1025 lcd_scroll_stop_line(current_vp, y);
1026
1027 if(!str || !str[0])
1028 return;
1029
1030 lcd_getstringsize(str, &w, &h);
1031 xpos = x*w / utf8length((char *)str);
1032 ypos = y*h;
1033 current_vp->drawmode = (style & STYLE_INVERT) ?
1034 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
1035 lcd_putsxyofs(xpos, ypos, offset, str);
1036 current_vp->drawmode ^= DRMODE_INVERSEVID;
1037 xrect = xpos + MAX(w - offset, 0);
1038 lcd_fillrect(xrect, ypos, current_vp->width - xrect, h);
1039 current_vp->drawmode = lastmode;
1040}
1041
1042/*** scrolling ***/
1043void lcd_puts_scroll(int x, int y, const unsigned char *string)
1044{
1045 lcd_puts_scroll_style(x, y, string, STYLE_DEFAULT);
1046}
1047
1048void lcd_puts_scroll_style(int x, int y, const unsigned char *string, int style)
1049{
1050 lcd_puts_scroll_style_offset(x, y, string, style, 0);
1051}
1052
1053void lcd_puts_scroll_offset(int x, int y, const unsigned char *string, int offset)
1054{
1055 lcd_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset);
1056}
1057
1058void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
1059 int style, int offset)
1060{
1061 struct scrollinfo* s;
1062 int w, h;
1063
1064 if ((unsigned)y >= (unsigned)current_vp->height)
1065 return;
1066
1067 /* remove any previously scrolling line at the same location */
1068 lcd_scroll_stop_line(current_vp, y);
1069
1070 if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return;
1071
1072 s = &lcd_scroll_info.scroll[lcd_scroll_info.lines];
1073
1074 s->start_tick = current_tick + lcd_scroll_info.delay;
1075 s->style = style;
1076 if (style & STYLE_INVERT) {
1077 lcd_puts_style_offset(x,y,string,STYLE_INVERT,offset);
1078 }
1079 else
1080 lcd_puts_offset(x,y,string,offset);
1081
1082 lcd_getstringsize(string, &w, &h);
1083
1084 if (current_vp->width - x * 8 < w) {
1085 /* prepare scroll line */
1086 char *end;
1087
1088 memset(s->line, 0, sizeof s->line);
1089 strcpy(s->line, (char *)string);
1090
1091 /* get width */
1092 s->width = lcd_getstringsize((unsigned char *)s->line, &w, &h);
1093
1094 /* scroll bidirectional or forward only depending on the string
1095 width */
1096 if ( lcd_scroll_info.bidir_limit ) {
1097 s->bidir = s->width < (current_vp->width) *
1098 (100 + lcd_scroll_info.bidir_limit) / 100;
1099 }
1100 else
1101 s->bidir = false;
1102
1103 if (!s->bidir) { /* add spaces if scrolling in the round */
1104 strcat(s->line, " ");
1105 /* get new width incl. spaces */
1106 s->width = lcd_getstringsize((unsigned char *)s->line, &w, &h);
1107 }
1108
1109 end = strchr(s->line, '\0');
1110 strlcpy(end, (char *)string, current_vp->width/2);
1111
1112 s->vp = current_vp;
1113 s->y = y;
1114 s->len = utf8length((char *)string);
1115 s->offset = offset;
1116 s->startx = x * s->width / s->len;
1117 s->backward = false;
1118 lcd_scroll_info.lines++;
1119 }
1120}
1121
1122void lcd_scroll_fn(void)
1123{
1124 struct font* pf;
1125 struct scrollinfo* s;
1126 int index;
1127 int xpos, ypos;
1128 int lastmode;
1129 struct viewport* old_vp = current_vp;
1130
1131 for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
1132 s = &lcd_scroll_info.scroll[index];
1133
1134 /* check pause */
1135 if (TIME_BEFORE(current_tick, s->start_tick))
1136 continue;
1137
1138 lcd_set_viewport(s->vp);
1139
1140 if (s->backward)
1141 s->offset -= lcd_scroll_info.step;
1142 else
1143 s->offset += lcd_scroll_info.step;
1144
1145 pf = font_get(current_vp->font);
1146 xpos = s->startx;
1147 ypos = s->y * pf->height;
1148
1149 if (s->bidir) { /* scroll bidirectional */
1150 if (s->offset <= 0) {
1151 /* at beginning of line */
1152 s->offset = 0;
1153 s->backward = false;
1154 s->start_tick = current_tick + lcd_scroll_info.delay * 2;
1155 }
1156 if (s->offset >= s->width - (current_vp->width - xpos)) {
1157 /* at end of line */
1158 s->offset = s->width - (current_vp->width - xpos);
1159 s->backward = true;
1160 s->start_tick = current_tick + lcd_scroll_info.delay * 2;
1161 }
1162 }
1163 else {
1164 /* scroll forward the whole time */
1165 if (s->offset >= s->width)
1166 s->offset %= s->width;
1167 }
1168
1169 lastmode = current_vp->drawmode;
1170 current_vp->drawmode = (s->style&STYLE_INVERT) ?
1171 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
1172 lcd_putsxyofs(xpos, ypos, s->offset, s->line);
1173 current_vp->drawmode = lastmode;
1174 lcd_update_viewport_rect(xpos, ypos, current_vp->width - xpos, pf->height);
1175 }
1176
1177 lcd_set_viewport(old_vp);
1178}
diff --git a/firmware/drivers/lcd-2bit-vert.c b/firmware/drivers/lcd-2bit-vert.c
index 57d27d2ead..7342cbd4ff 100644
--- a/firmware/drivers/lcd-2bit-vert.c
+++ b/firmware/drivers/lcd-2bit-vert.c
@@ -404,7 +404,7 @@ void lcd_clear_viewport(void)
404 lastmode = current_vp->drawmode; 404 lastmode = current_vp->drawmode;
405 405
406 /* Invert the INVERSEVID bit and set basic mode to SOLID */ 406 /* Invert the INVERSEVID bit and set basic mode to SOLID */
407 current_vp->drawmode = (~lastmode & DRMODE_INVERSEVID) | 407 current_vp->drawmode = (~lastmode & DRMODE_INVERSEVID) |
408 DRMODE_SOLID; 408 DRMODE_SOLID;
409 409
410 lcd_fillrect(0, 0, current_vp->width, current_vp->height); 410 lcd_fillrect(0, 0, current_vp->width, current_vp->height);
@@ -1002,226 +1002,4 @@ void lcd_bitmap(const fb_data *src, int x, int y, int width, int height)
1002 lcd_bitmap_part(src, 0, 0, width, x, y, width, height); 1002 lcd_bitmap_part(src, 0, 0, width, x, y, width, height);
1003} 1003}
1004 1004
1005/* put a string at a given pixel position, skipping first ofs pixel columns */ 1005#include "lcd-bitmap-common.c"
1006static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
1007{
1008 unsigned short ch;
1009 unsigned short *ucs;
1010 struct font* pf = font_get(current_vp->font);
1011
1012 ucs = bidi_l2v(str, 1);
1013
1014 while ((ch = *ucs++) != 0 && x < current_vp->width)
1015 {
1016 int width;
1017 const unsigned char *bits;
1018
1019 /* get proportional width and glyph bits */
1020 width = font_get_width(pf,ch);
1021
1022 if (ofs > width)
1023 {
1024 ofs -= width;
1025 continue;
1026 }
1027
1028 bits = font_get_bits(pf, ch);
1029
1030 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs,
1031 pf->height);
1032
1033 x += width - ofs;
1034 ofs = 0;
1035 }
1036}
1037
1038/* put a string at a given pixel position */
1039void lcd_putsxy(int x, int y, const unsigned char *str)
1040{
1041 lcd_putsxyofs(x, y, 0, str);
1042}
1043
1044/*** line oriented text output ***/
1045
1046/* put a string at a given char position */
1047void lcd_puts(int x, int y, const unsigned char *str)
1048{
1049 lcd_puts_style_offset(x, y, str, STYLE_DEFAULT, 0);
1050}
1051
1052void lcd_puts_style(int x, int y, const unsigned char *str, int style)
1053{
1054 lcd_puts_style_offset(x, y, str, style, 0);
1055}
1056
1057void lcd_puts_offset(int x, int y, const unsigned char *str, int offset)
1058{
1059 lcd_puts_style_offset(x, y, str, STYLE_DEFAULT, offset);
1060}
1061
1062/* put a string at a given char position, style, and pixel position,
1063 * skipping first offset pixel columns */
1064void lcd_puts_style_offset(int x, int y, const unsigned char *str,
1065 int style, int offset)
1066{
1067 int xpos,ypos,w,h,xrect;
1068 int lastmode = current_vp->drawmode;
1069
1070 /* make sure scrolling is turned off on the line we are updating */
1071 lcd_scroll_stop_line(current_vp, y);
1072
1073 if(!str || !str[0])
1074 return;
1075
1076 lcd_getstringsize(str, &w, &h);
1077 xpos = x*w / utf8length((char *)str);
1078 ypos = y*h;
1079 current_vp->drawmode = (style & STYLE_INVERT) ?
1080 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
1081 lcd_putsxyofs(xpos, ypos, offset, str);
1082 current_vp->drawmode ^= DRMODE_INVERSEVID;
1083 xrect = xpos + MAX(w - offset, 0);
1084 lcd_fillrect(xrect, ypos, current_vp->width - xrect, h);
1085 current_vp->drawmode = lastmode;
1086}
1087
1088/*** scrolling ***/
1089
1090void lcd_puts_scroll(int x, int y, const unsigned char *string)
1091{
1092 lcd_puts_scroll_style(x, y, string, STYLE_DEFAULT);
1093}
1094
1095void lcd_puts_scroll_style(int x, int y, const unsigned char *string, int style)
1096{
1097 lcd_puts_scroll_style_offset(x, y, string, style, 0);
1098}
1099
1100void lcd_puts_scroll_offset(int x, int y, const unsigned char *string, int offset)
1101{
1102 lcd_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset);
1103}
1104
1105void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
1106 int style, int offset)
1107{
1108 struct scrollinfo* s;
1109 int w, h;
1110
1111 if ((unsigned)y >= (unsigned)current_vp->height)
1112 return;
1113
1114 /* remove any previously scrolling line at the same location */
1115 lcd_scroll_stop_line(current_vp, y);
1116
1117 if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return;
1118
1119 s = &lcd_scroll_info.scroll[lcd_scroll_info.lines];
1120
1121 s->start_tick = current_tick + lcd_scroll_info.delay;
1122 s->style = style;
1123 if (style & STYLE_INVERT) {
1124 lcd_puts_style_offset(x,y,string,STYLE_INVERT,offset);
1125 }
1126 else
1127 lcd_puts_offset(x,y,string,offset);
1128
1129 lcd_getstringsize(string, &w, &h);
1130
1131 if (current_vp->width - x * 8< w) {
1132 /* prepare scroll line */
1133 char *end;
1134
1135 memset(s->line, 0, sizeof s->line);
1136 strcpy(s->line, (char *)string);
1137
1138 /* get width */
1139 s->width = lcd_getstringsize((unsigned char *)s->line, &w, &h);
1140
1141 /* scroll bidirectional or forward only depending on the string
1142 width */
1143 if ( lcd_scroll_info.bidir_limit ) {
1144 s->bidir = s->width < (current_vp->width) *
1145 (100 + lcd_scroll_info.bidir_limit) / 100;
1146 }
1147 else
1148 s->bidir = false;
1149
1150 if (!s->bidir) { /* add spaces if scrolling in the round */
1151 strcat(s->line, " ");
1152 /* get new width incl. spaces */
1153 s->width = lcd_getstringsize((unsigned char *)s->line, &w, &h);
1154 }
1155
1156 end = strchr(s->line, '\0');
1157 strlcpy(end, (char *)string, current_vp->width/2);
1158
1159 s->vp = current_vp;
1160 s->y = y;
1161 s->len = utf8length((char *)string);
1162 s->offset = offset;
1163 s->startx = x * s->width / s->len;
1164 s->backward = false;
1165
1166 lcd_scroll_info.lines++;
1167 }
1168}
1169
1170void lcd_scroll_fn(void)
1171{
1172 struct font* pf;
1173 struct scrollinfo* s;
1174 int index;
1175 int xpos, ypos;
1176 int lastmode;
1177 struct viewport* old_vp = current_vp;
1178
1179 for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
1180 s = &lcd_scroll_info.scroll[index];
1181
1182 /* check pause */
1183 if (TIME_BEFORE(current_tick, s->start_tick))
1184 continue;
1185
1186 lcd_set_viewport(s->vp);
1187
1188 if (s->backward)
1189 s->offset -= lcd_scroll_info.step;
1190 else
1191 s->offset += lcd_scroll_info.step;
1192
1193 pf = font_get(current_vp->font);
1194 xpos = s->startx;
1195 ypos = s->y * pf->height;
1196
1197 if (s->bidir) { /* scroll bidirectional */
1198 if (s->offset <= 0) {
1199 /* at beginning of line */
1200 s->offset = 0;
1201 s->backward = false;
1202 s->start_tick = current_tick + lcd_scroll_info.delay * 2;
1203 }
1204 if (s->offset >= s->width - (current_vp->width - xpos)) {
1205 /* at end of line */
1206 s->offset = s->width - (current_vp->width - xpos);
1207 s->backward = true;
1208 s->start_tick = current_tick + lcd_scroll_info.delay * 2;
1209 }
1210 }
1211 else {
1212 /* scroll forward the whole time */
1213 if (s->offset >= s->width)
1214 s->offset %= s->width;
1215 }
1216
1217 lastmode = current_vp->drawmode;
1218 current_vp->drawmode = (s->style&STYLE_INVERT) ?
1219 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
1220 lcd_putsxyofs(xpos, ypos, s->offset, s->line);
1221 current_vp->drawmode = lastmode;
1222 lcd_update_viewport_rect(xpos, ypos,
1223 current_vp->width - xpos, pf->height);
1224 }
1225
1226 lcd_set_viewport(old_vp);
1227}
diff --git a/firmware/drivers/lcd-2bit-vi.c b/firmware/drivers/lcd-2bit-vi.c
index 0a73f0dd25..47f755f240 100644
--- a/firmware/drivers/lcd-2bit-vi.c
+++ b/firmware/drivers/lcd-2bit-vi.c
@@ -66,7 +66,7 @@ static struct viewport default_vp =
66 .bg_pattern = LCDM(DEFAULT_BG) 66 .bg_pattern = LCDM(DEFAULT_BG)
67}; 67};
68 68
69static struct viewport *current_vp IBSS_ATTR; 69static struct viewport * current_vp IBSS_ATTR;
70 70
71static unsigned fg_pattern IBSS_ATTR; 71static unsigned fg_pattern IBSS_ATTR;
72static unsigned bg_pattern IBSS_ATTR; 72static unsigned bg_pattern IBSS_ATTR;
@@ -1016,225 +1016,4 @@ void LCDFN(bitmap)(const FBFN(data) *src, int x, int y, int width, int height)
1016 LCDFN(bitmap_part)(src, 0, 0, width, x, y, width, height); 1016 LCDFN(bitmap_part)(src, 0, 0, width, x, y, width, height);
1017} 1017}
1018 1018
1019/* put a string at a given pixel position, skipping first ofs pixel columns */ 1019#include "lcd-bitmap-common.c"
1020static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str)
1021{
1022 unsigned short ch;
1023 unsigned short *ucs;
1024 struct font* pf = font_get(current_vp->font);
1025
1026 ucs = bidi_l2v(str, 1);
1027
1028 while ((ch = *ucs++) != 0 && x < current_vp->width)
1029 {
1030 int width;
1031 const unsigned char *bits;
1032
1033 /* get proportional width and glyph bits */
1034 width = font_get_width(pf, ch);
1035
1036 if (ofs > width)
1037 {
1038 ofs -= width;
1039 continue;
1040 }
1041
1042 bits = font_get_bits(pf, ch);
1043
1044 LCDFN(mono_bitmap_part)(bits, ofs, 0, width, x, y, width - ofs,
1045 pf->height);
1046
1047 x += width - ofs;
1048 ofs = 0;
1049 }
1050}
1051
1052/* put a string at a given pixel position */
1053void LCDFN(putsxy)(int x, int y, const unsigned char *str)
1054{
1055 LCDFN(putsxyofs)(x, y, 0, str);
1056}
1057
1058/*** line oriented text output ***/
1059
1060/* put a string at a given char position */
1061void LCDFN(puts)(int x, int y, const unsigned char *str)
1062{
1063 LCDFN(puts_style_offset)(x, y, str, STYLE_DEFAULT, 0);
1064}
1065
1066void LCDFN(puts_style)(int x, int y, const unsigned char *str, int style)
1067{
1068 LCDFN(puts_style_offset)(x, y, str, style, 0);
1069}
1070
1071void LCDFN(puts_offset)(int x, int y, const unsigned char *str, int offset)
1072{
1073 LCDFN(puts_style_offset)(x, y, str, STYLE_DEFAULT, offset);
1074}
1075
1076/* put a string at a given char position, style, and pixel position,
1077 * skipping first offset pixel columns */
1078void LCDFN(puts_style_offset)(int x, int y, const unsigned char *str,
1079 int style, int offset)
1080{
1081 int xpos,ypos,w,h,xrect;
1082 int lastmode = current_vp->drawmode;
1083
1084 /* make sure scrolling is turned off on the line we are updating */
1085 LCDFN(scroll_stop_line)(current_vp, y);
1086
1087 if(!str || !str[0])
1088 return;
1089
1090 LCDFN(getstringsize)(str, &w, &h);
1091 xpos = x*w / utf8length((char *)str);
1092 ypos = y*h;
1093 current_vp->drawmode = (style & STYLE_INVERT) ?
1094 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
1095 LCDFN(putsxyofs)(xpos, ypos, offset, str);
1096 current_vp->drawmode ^= DRMODE_INVERSEVID;
1097 xrect = xpos + MAX(w - offset, 0);
1098 LCDFN(fillrect)(xrect, ypos, current_vp->width - xrect, h);
1099 current_vp->drawmode = lastmode;
1100}
1101
1102/*** scrolling ***/
1103void LCDFN(puts_scroll)(int x, int y, const unsigned char *string)
1104{
1105 LCDFN(puts_scroll_style)(x, y, string, STYLE_DEFAULT);
1106}
1107
1108void LCDFN(puts_scroll_style)(int x, int y, const unsigned char *string, int style)
1109{
1110 LCDFN(puts_scroll_style_offset)(x, y, string, style, 0);
1111}
1112
1113void LCDFN(puts_scroll_offset)(int x, int y, const unsigned char *string, int offset)
1114{
1115 LCDFN(puts_scroll_style_offset)(x, y, string, STYLE_DEFAULT, offset);
1116}
1117
1118void LCDFN(puts_scroll_style_offset)(int x, int y, const unsigned char *string,
1119 int style, int offset)
1120{
1121 struct scrollinfo* s;
1122 int w, h;
1123
1124 if ((unsigned)y >= (unsigned)current_vp->height)
1125 return;
1126
1127 /* remove any previously scrolling line at the same location */
1128 LCDFN(scroll_stop_line)(current_vp, y);
1129
1130 if (LCDFN(scroll_info).lines >= LCDM(SCROLLABLE_LINES)) return;
1131
1132 s = &LCDFN(scroll_info).scroll[LCDFN(scroll_info).lines];
1133
1134 s->start_tick = current_tick + LCDFN(scroll_info).delay;
1135 s->style = style;
1136 if (style & STYLE_INVERT) {
1137 LCDFN(puts_style_offset)(x,y,string,STYLE_INVERT,offset);
1138 }
1139 else
1140 LCDFN(puts_offset)(x,y,string,offset);
1141
1142 LCDFN(getstringsize)(string, &w, &h);
1143
1144 if (current_vp->width - x * 8 < w) {
1145 /* prepare scroll line */
1146 char *end;
1147
1148 memset(s->line, 0, sizeof s->line);
1149 strcpy(s->line, string);
1150
1151 /* get width */
1152 s->width = LCDFN(getstringsize)(s->line, &w, &h);
1153
1154 /* scroll bidirectional or forward only depending on the string
1155 width */
1156 if ( LCDFN(scroll_info).bidir_limit ) {
1157 s->bidir = s->width < (current_vp->width) *
1158 (100 + LCDFN(scroll_info).bidir_limit) / 100;
1159 }
1160 else
1161 s->bidir = false;
1162
1163 if (!s->bidir) { /* add spaces if scrolling in the round */
1164 strcat(s->line, " ");
1165 /* get new width incl. spaces */
1166 s->width = LCDFN(getstringsize)(s->line, &w, &h);
1167 }
1168
1169 end = strchr(s->line, '\0');
1170 strlcpy(end, (char *)string, current_vp->width/2);
1171
1172 s->vp = current_vp;
1173 s->y = y;
1174 s->len = utf8length((char *)string);
1175 s->offset = offset;
1176 s->startx = x * s->width / s->len;
1177 s->backward = false;
1178
1179 LCDFN(scroll_info).lines++;
1180 }
1181}
1182
1183void LCDFN(scroll_fn)(void)
1184{
1185 struct font* pf;
1186 struct scrollinfo* s;
1187 int index;
1188 int xpos, ypos;
1189 int lastmode;
1190 struct viewport* old_vp = current_vp;
1191
1192 for ( index = 0; index < LCDFN(scroll_info).lines; index++ ) {
1193 s = &LCDFN(scroll_info).scroll[index];
1194
1195 /* check pause */
1196 if (TIME_BEFORE(current_tick, s->start_tick))
1197 continue;
1198
1199 LCDFN(set_viewport)(s->vp);
1200
1201 if (s->backward)
1202 s->offset -= LCDFN(scroll_info).step;
1203 else
1204 s->offset += LCDFN(scroll_info).step;
1205
1206 pf = font_get(current_vp->font);
1207 xpos = s->startx;
1208 ypos = s->y * pf->height;
1209
1210 if (s->bidir) { /* scroll bidirectional */
1211 if (s->offset <= 0) {
1212 /* at beginning of line */
1213 s->offset = 0;
1214 s->backward = false;
1215 s->start_tick = current_tick + LCDFN(scroll_info).delay * 2;
1216 }
1217 if (s->offset >= s->width - (current_vp->width - xpos)) {
1218 /* at end of line */
1219 s->offset = s->width - (current_vp->width - xpos);
1220 s->backward = true;
1221 s->start_tick = current_tick + LCDFN(scroll_info).delay * 2;
1222 }
1223 }
1224 else {
1225 /* scroll forward the whole time */
1226 if (s->offset >= s->width)
1227 s->offset %= s->width;
1228 }
1229
1230 lastmode = current_vp->drawmode;
1231 current_vp->drawmode = (s->style&STYLE_INVERT) ?
1232 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
1233 LCDFN(putsxyofs)(xpos, ypos, s->offset, s->line);
1234 current_vp->drawmode = lastmode;
1235 LCDFN(update_viewport_rect)(xpos, ypos,
1236 current_vp->width - xpos, pf->height);
1237 }
1238
1239 LCDFN(set_viewport)(old_vp);
1240}
diff --git a/firmware/drivers/lcd-bitmap-common.c b/firmware/drivers/lcd-bitmap-common.c
new file mode 100644
index 0000000000..c1efd9097e
--- /dev/null
+++ b/firmware/drivers/lcd-bitmap-common.c
@@ -0,0 +1,329 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 * Text rendering
12 * Copyright (C) 2006 Shachar Liberman
13 * Offset text, scrolling
14 * Copyright (C) 2007 Nicolas Pennequin, Tom Ross, Ken Fazzone, Akio Idehara
15 * Color gradient background
16 * Copyright (C) 2009 Andrew Mahone
17 * Merged common LCD bitmap code
18 *
19 * Rockbox common bitmap LCD functions
20 *
21 * This program is free software; you can redistribute it and/or
22 * modify it under the terms of the GNU General Public License
23 * as published by the Free Software Foundation; either version 2
24 * of the License, or (at your option) any later version.
25 *
26 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
27 * KIND, either express or implied.
28 *
29 ****************************************************************************/
30
31#ifndef LCDFN /* Not compiling for remote - define macros for main LCD. */
32#define LCDFN(fn) lcd_ ## fn
33#define FBFN(fn) fb_ ## fn
34#define LCDM(ma) LCD_ ## ma
35#define LCDNAME "lcd_"
36#define MAIN_LCD
37#endif
38
39#if defined(MAIN_LCD) && defined(HAVE_LCD_COLOR)
40/* Fill a rectangle with a gradient */
41static void lcd_gradient_rect(int x1, int x2, int y, unsigned h,
42 int num_lines, int cur_line)
43{
44 int old_pattern = current_vp->fg_pattern;
45 int step_mul;
46 if (h == 0) return;
47
48 num_lines *= h;
49 cur_line *= h;
50 step_mul = (1 << 16) / (num_lines);
51 int h_r = RGB_UNPACK_RED(current_vp->lss_pattern);
52 int h_g = RGB_UNPACK_GREEN(current_vp->lss_pattern);
53 int h_b = RGB_UNPACK_BLUE(current_vp->lss_pattern);
54 int rstep = (h_r - RGB_UNPACK_RED(current_vp->lse_pattern)) * step_mul;
55 int gstep = (h_g - RGB_UNPACK_GREEN(current_vp->lse_pattern)) * step_mul;
56 int bstep = (h_b - RGB_UNPACK_BLUE(current_vp->lse_pattern)) * step_mul;
57 h_r = (h_r << 16) + (1 << 15);
58 h_g = (h_g << 16) + (1 << 15);
59 h_b = (h_b << 16) + (1 << 15);
60 if (cur_line)
61 {
62 h_r -= cur_line * rstep;
63 h_g -= cur_line * gstep;
64 h_b -= cur_line * bstep;
65 }
66 unsigned count;
67
68 for(count = 0; count < h; count++) {
69 current_vp->fg_pattern = LCD_RGBPACK(h_r >> 16, h_g >> 16, h_b >> 16);
70 lcd_hline(x1, x2, y + count);
71 h_r -= rstep;
72 h_g -= gstep;
73 h_b -= bstep;
74 }
75
76 current_vp->fg_pattern = old_pattern;
77}
78#endif
79
80/* put a string at a given pixel position, skipping first ofs pixel columns */
81static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str)
82{
83 unsigned short ch;
84 unsigned short *ucs;
85 struct font* pf = font_get(current_vp->font);
86
87 ucs = bidi_l2v(str, 1);
88
89 while ((ch = *ucs++) != 0 && x < current_vp->width)
90 {
91 int width;
92 const unsigned char *bits;
93
94 /* get proportional width and glyph bits */
95 width = font_get_width(pf, ch);
96
97 if (ofs > width)
98 {
99 ofs -= width;
100 continue;
101 }
102
103 bits = font_get_bits(pf, ch);
104
105 LCDFN(mono_bitmap_part)(bits, ofs, 0, width, x, y, width - ofs,
106 pf->height);
107
108 x += width - ofs;
109 ofs = 0;
110 }
111}
112/* put a string at a given pixel position */
113void LCDFN(putsxy)(int x, int y, const unsigned char *str)
114{
115 LCDFN(putsxyofs)(x, y, 0, str);
116}
117
118static void LCDFN(putsxyofs_style)(int xpos, int ypos,
119 const unsigned char *str, int style,
120 int w, int h, int offset)
121{
122 int lastmode = current_vp->drawmode;
123 int xrect = xpos + MAX(w - offset, 0);
124#if defined(MAIN_LCD) && defined(HAVE_LCD_COLOR)
125 int oldfgcolor = current_vp->fg_pattern;
126 int oldbgcolor = current_vp->bg_pattern;
127 current_vp->drawmode = DRMODE_SOLID | ((style & STYLE_INVERT) ?
128 DRMODE_INVERSEVID : 0);
129 if (style & STYLE_COLORED) {
130 if (current_vp->drawmode == DRMODE_SOLID)
131 current_vp->fg_pattern = style & STYLE_COLOR_MASK;
132 else
133 current_vp->bg_pattern = style & STYLE_COLOR_MASK;
134 }
135 current_vp->drawmode ^= DRMODE_INVERSEVID;
136 if (style & STYLE_GRADIENT) {
137 current_vp->drawmode = DRMODE_FG;
138 lcd_gradient_rect(xpos, current_vp->width, ypos, h,
139 NUMLN_UNPACK(style), CURLN_UNPACK(style));
140 current_vp->fg_pattern = current_vp->lst_pattern;
141 }
142 else if (style & STYLE_COLORBAR) {
143 current_vp->drawmode = DRMODE_FG;
144 current_vp->fg_pattern = current_vp->lss_pattern;
145 lcd_fillrect(xpos, ypos, current_vp->width - xpos, h);
146 current_vp->fg_pattern = current_vp->lst_pattern;
147 }
148 else {
149 lcd_fillrect(xrect, ypos, current_vp->width - xrect, h);
150 current_vp->drawmode = (style & STYLE_INVERT) ?
151 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
152 }
153 lcd_putsxyofs(xpos, ypos, offset, str);
154 current_vp->fg_pattern = oldfgcolor;
155 current_vp->bg_pattern = oldbgcolor;
156#else
157 current_vp->drawmode = DRMODE_SOLID | ((style & STYLE_INVERT) ?
158 0 : DRMODE_INVERSEVID);
159 LCDFN(fillrect)(xrect, ypos, current_vp->width - xrect, h);
160 current_vp->drawmode ^= DRMODE_INVERSEVID;
161 LCDFN(putsxyofs)(xpos, ypos, offset, str);
162#endif
163 current_vp->drawmode = lastmode;
164}
165
166/*** Line oriented text output ***/
167
168/* put a string at a given char position */
169void LCDFN(puts_style_offset)(int x, int y, const unsigned char *str,
170 int style, int offset)
171{
172 int xpos, ypos, w, h;
173 LCDFN(scroll_stop_line)(current_vp, y);
174 if(!str || !str[0])
175 return;
176 LCDFN(getstringsize)(str, &w, &h);
177 xpos = x * w / utf8length((char *)str);
178 ypos = y * h;
179 LCDFN(putsxyofs_style)(xpos, ypos, str, style, w, h, offset);
180}
181
182void LCDFN(puts)(int x, int y, const unsigned char *str)
183{
184 LCDFN(puts_style_offset)(x, y, str, STYLE_DEFAULT, 0);
185}
186
187void LCDFN(puts_style)(int x, int y, const unsigned char *str, int style)
188{
189 LCDFN(puts_style_offset)(x, y, str, style, 0);
190}
191
192void LCDFN(puts_offset)(int x, int y, const unsigned char *str, int offset)
193{
194 LCDFN(puts_style_offset)(x, y, str, STYLE_DEFAULT, offset);
195}
196
197/*** scrolling ***/
198
199void LCDFN(puts_scroll_style_offset)(int x, int y, const unsigned char *string,
200 int style, int offset)
201{
202 int w, h;
203
204 if ((unsigned)y >= (unsigned)current_vp->height)
205 return;
206
207 /* remove any previously scrolling line at the same location */
208 lcd_scroll_stop_line(current_vp, y);
209
210 if (LCDFN(scroll_info.lines) >= LCDM(SCROLLABLE_LINES)) return;
211 if (!string)
212 return;
213 LCDFN(puts_style_offset)(x, y, string, style, offset);
214
215 LCDFN(getstringsize)(string, &w, &h);
216
217 if (current_vp->width - x * 8 < w) {
218 /* prepare scroll line */
219 struct scrollinfo* s;
220 s = &LCDFN(scroll_info).scroll[LCDFN(scroll_info).lines];
221 s->start_tick = current_tick + LCDFN(scroll_info).delay;
222 s->style = style;
223
224 char *end;
225
226 memset(s->line, 0, sizeof s->line);
227 strcpy(s->line, string);
228
229 /* get width */
230 s->width = LCDFN(getstringsize)(s->line, &w, &h);
231
232 /* scroll bidirectional or forward only depending on the string
233 width */
234 if ( LCDFN(scroll_info).bidir_limit ) {
235 s->bidir = s->width < (current_vp->width) *
236 (100 + LCDFN(scroll_info).bidir_limit) / 100;
237 }
238 else
239 s->bidir = false;
240
241 if (!s->bidir) { /* add spaces if scrolling in the round */
242 strcat(s->line, " ");
243 /* get new width incl. spaces */
244 s->width = LCDFN(getstringsize)(s->line, &w, &h);
245 }
246
247 end = strchr(s->line, '\0');
248 strlcpy(end, string, current_vp->width/2);
249
250 s->vp = current_vp;
251 s->y = y;
252 s->len = utf8length(string);
253 s->offset = offset;
254 s->startx = x * s->width / s->len;
255 s->backward = false;
256
257 LCDFN(scroll_info).lines++;
258 }
259}
260
261void LCDFN(puts_scroll)(int x, int y, const unsigned char *string)
262{
263 LCDFN(puts_scroll_style)(x, y, string, STYLE_DEFAULT);
264}
265
266void LCDFN(puts_scroll_style)(int x, int y, const unsigned char *string,
267 int style)
268{
269 LCDFN(puts_scroll_style_offset)(x, y, string, style, 0);
270}
271
272void LCDFN(puts_scroll_offset)(int x, int y, const unsigned char *string,
273 int offset)
274{
275 LCDFN(puts_scroll_style_offset)(x, y, string, STYLE_DEFAULT, offset);
276}
277
278void LCDFN(scroll_fn)(void)
279{
280 struct font* pf;
281 struct scrollinfo* s;
282 int index;
283 int xpos, ypos;
284 struct viewport* old_vp = current_vp;
285
286 for ( index = 0; index < LCDFN(scroll_info).lines; index++ ) {
287 s = &LCDFN(scroll_info).scroll[index];
288
289 /* check pause */
290 if (TIME_BEFORE(current_tick, s->start_tick))
291 continue;
292
293 LCDFN(set_viewport)(s->vp);
294
295 if (s->backward)
296 s->offset -= LCDFN(scroll_info).step;
297 else
298 s->offset += LCDFN(scroll_info).step;
299
300 pf = font_get(current_vp->font);
301 xpos = s->startx;
302 ypos = s->y * pf->height;
303
304 if (s->bidir) { /* scroll bidirectional */
305 if (s->offset <= 0) {
306 /* at beginning of line */
307 s->offset = 0;
308 s->backward = false;
309 s->start_tick = current_tick + LCDFN(scroll_info).delay * 2;
310 }
311 if (s->offset >= s->width - (current_vp->width - xpos)) {
312 /* at end of line */
313 s->offset = s->width - (current_vp->width - xpos);
314 s->backward = true;
315 s->start_tick = current_tick + LCDFN(scroll_info).delay * 2;
316 }
317 }
318 else {
319 /* scroll forward the whole time */
320 if (s->offset >= s->width)
321 s->offset %= s->width;
322 }
323 LCDFN(putsxyofs_style)(xpos, ypos, s->line, s->style, s->width,
324 pf->height, s->offset);
325 LCDFN(update_viewport_rect)(xpos, ypos, current_vp->width - xpos,
326 pf->height);
327 }
328 LCDFN(set_viewport)(old_vp);
329}