A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 319 lines 8.4 kB view raw
1/*************************************************************************** 2* __________ __ ___. 3* Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7* \/ \/ \/ \/ \/ 8* $Id$ 9* 10* Copyright (C) 2010 Teruaki Kawashima 11* 12* This program is free software; you can redistribute it and/or 13* modify it under the terms of the GNU General Public License 14* as published by the Free Software Foundation; either version 2 15* of the License, or (at your option) any later version. 16* 17* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18* KIND, either express or implied. 19* 20****************************************************************************/ 21 22#include "config.h" 23#include "plugin.h" 24#include "pluginlib_actions.h" 25#include "simple_viewer.h" 26#include <ctype.h> 27 28 29struct view_info { 30 struct font* pf; 31 struct viewport scrollbar_vp; /* viewport for scrollbar */ 32 struct viewport vp; 33 const char *title; 34 const char *text; /* displayed text */ 35 int display_lines; /* number of lines can be displayed */ 36 int line_count; /* number of lines */ 37 int line; /* current first line */ 38 int start; /* possition of first line in text */ 39}; 40 41static bool isbrchr(const unsigned char *str, int len) 42{ 43 const unsigned char *p = "!,-.:;? 、。!,.:;?―"; 44 if (isspace(*str)) 45 return true; 46 47 while(*p) 48 { 49 int n = rb->utf8seek(p, 1); 50 if (len == n && !rb->strncmp(p, str, len)) 51 return true; 52 p += n; 53 } 54 return false; 55} 56 57static const char* get_next_line(const char *text, struct view_info *info) 58{ 59 const char *ptr = text; 60 const char *space = NULL; 61 int total, n, w; 62 total = 0; 63 while(*ptr) 64 { 65 ucschar_t ch; 66 n = ((intptr_t)rb->utf8decode(ptr, &ch) - (intptr_t)ptr); 67 if (rb->is_diacritic(ch, NULL)) 68 w = 0; 69 else 70 w = rb->font_get_width(info->pf, ch); 71 if (isbrchr(ptr, n)) 72 space = ptr+(isspace(*ptr) || total + w <= info->vp.width? n: 0); 73 if (*ptr == '\n') 74 { 75 ptr += n; 76 break; 77 } 78 if (total + w > info->vp.width) 79 break; 80 ptr += n; 81 total += w; 82 } 83 return *ptr && space? space: ptr; 84} 85 86static void calc_line_count(struct view_info *info) 87{ 88 const char *ptr = info->text; 89 int i = 0; 90 bool scrollbar = false; 91 92 while (*ptr) 93 { 94 ptr = get_next_line(ptr, info); 95 i++; 96 if (!scrollbar && i > info->display_lines) 97 { 98 ptr = info->text; 99 i = 0; 100 info->scrollbar_vp = info->vp; 101 info->scrollbar_vp.width = rb->global_settings->scrollbar_width; 102 info->vp.width -= info->scrollbar_vp.width; 103 if (rb->global_settings->scrollbar != SCROLLBAR_RIGHT) 104 info->vp.x = info->scrollbar_vp.width; 105 else 106 info->scrollbar_vp.x = info->vp.width; 107 scrollbar = true; 108 } 109 } 110 info->line_count = i; 111} 112 113static void calc_first_line(struct view_info *info, int line) 114{ 115 const char *ptr = info->text; 116 int i = 0; 117 118 if (line > info->line_count - info->display_lines) 119 line = info->line_count - info->display_lines; 120 if (line < 0) 121 line = 0; 122 123 if (info->line <= line) 124 { 125 ptr += info->start; 126 i = info->line; 127 } 128 while (*ptr && i < line) 129 { 130 ptr = get_next_line(ptr, info); 131 i++; 132 } 133 info->start = ptr - info->text; 134 info->line = i; 135} 136 137static int init_view(struct view_info *info, 138 const char *title, const char *text) 139{ 140 rb->viewport_set_defaults(&info->vp, SCREEN_MAIN); 141 info->pf = rb->font_get(rb->screens[SCREEN_MAIN]->getuifont()); 142 info->display_lines = info->vp.height / info->pf->height; 143 144 info->title = title; 145 info->text = text; 146 info->line_count = 0; 147 info->line = 0; 148 info->start = 0; 149 150 /* no title for small screens. */ 151 if (info->display_lines < 4) 152 { 153 info->title = NULL; 154 } 155 else 156 { 157 info->display_lines--; 158 info->vp.y += info->pf->height; 159 info->vp.height -= info->pf->height; 160 } 161 162 calc_line_count(info); 163 return 0; 164} 165 166static void draw_text(struct view_info *info) 167{ 168#define OUTPUT_SIZE LCD_WIDTH+1 169 static char output[OUTPUT_SIZE]; 170 const char *text, *ptr; 171 int max_show, line; 172 struct screen* display = rb->screens[SCREEN_MAIN]; 173 174 /* clear screen */ 175 display->clear_display(); 176 177 /* display title. */ 178 if(info->title) 179 { 180 display->set_viewport(NULL); 181 display->puts(0, 0, info->title); 182 } 183 184 max_show = MIN(info->line_count - info->line, info->display_lines); 185 text = info->text + info->start; 186 187 display->set_viewport(&info->vp); 188 for (line = 0; line < max_show; line++) 189 { 190 int len; 191 ptr = get_next_line(text, info); 192 len = ptr-text; 193 while(len > 0 && isspace(text[len-1])) 194 len--; 195 rb->memcpy(output, text, len); 196 output[len] = 0; 197 display->puts(0, line, output); 198 text = ptr; 199 } 200 if (info->line_count > info->display_lines) 201 { 202 display->set_viewport(&info->scrollbar_vp); 203 rb->gui_scrollbar_draw(display, (info->scrollbar_vp.width? 0: 1), 0, 204 info->scrollbar_vp.width - 1, info->scrollbar_vp.height, 205 info->line_count, info->line, info->line + max_show, 206 VERTICAL); 207 } 208 209 display->set_viewport(NULL); 210 display->update(); 211} 212 213static void scroll_up(struct view_info *info, int n) 214{ 215 if (info->line <= 0) 216 return; 217 218 calc_first_line(info, info->line-n); 219 draw_text(info); 220 rb->yield(); 221} 222 223static void scroll_down(struct view_info *info, int n) 224{ 225 if (info->line + info->display_lines >= info->line_count) 226 return; 227 228 calc_first_line(info, info->line+n); 229 draw_text(info); 230 rb->yield(); 231} 232 233static void scroll_to_top(struct view_info *info) 234{ 235 if (info->line <= 0) 236 return; 237 238 calc_first_line(info, 0); 239 draw_text(info); 240} 241 242static void scroll_to_bottom(struct view_info *info) 243{ 244 if (info->line + info->display_lines >= info->line_count) 245 return; 246 247 calc_first_line(info, info->line_count - info->display_lines); 248 draw_text(info); 249} 250 251int view_text(const char *title, const char *text) 252{ 253 struct view_info info; 254 const struct button_mapping *view_contexts[] = { 255 pla_main_ctx, 256 }; 257 int button; 258 259 init_view(&info, title, text); 260 draw_text(&info); 261 262 /* wait for keypress */ 263 while(1) 264 { 265 button = pluginlib_getaction(TIMEOUT_BLOCK, view_contexts, 266 ARRAYLEN(view_contexts)); 267 switch (button) 268 { 269 case PLA_UP: 270#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ 271 || (CONFIG_KEYPAD == IPOD_3G_PAD) \ 272 || (CONFIG_KEYPAD == IPOD_4G_PAD) 273 return PLUGIN_OK; 274#endif 275 case PLA_UP_REPEAT: 276#ifdef HAVE_SCROLLWHEEL 277 case PLA_SCROLL_BACK: 278 case PLA_SCROLL_BACK_REPEAT: 279#endif 280 scroll_up(&info, 1); 281 break; 282 case PLA_DOWN: 283 case PLA_DOWN_REPEAT: 284#ifdef HAVE_SCROLLWHEEL 285 case PLA_SCROLL_FWD: 286 case PLA_SCROLL_FWD_REPEAT: 287#endif 288 scroll_down(&info, 1); 289 break; 290 case PLA_LEFT: 291#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ 292 || (CONFIG_KEYPAD == IPOD_3G_PAD) \ 293 || (CONFIG_KEYPAD == IPOD_4G_PAD) 294 return PLUGIN_OK; 295#endif 296 scroll_up(&info, info.display_lines); 297 break; 298 case PLA_RIGHT: 299 scroll_down(&info, info.display_lines); 300 break; 301 case PLA_LEFT_REPEAT: 302 scroll_to_top(&info); 303 break; 304 case PLA_RIGHT_REPEAT: 305 scroll_to_bottom(&info); 306 break; 307 case PLA_SELECT: 308 case PLA_EXIT: 309 case PLA_CANCEL: 310 return PLUGIN_OK; 311 default: 312 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) 313 return PLUGIN_USB_CONNECTED; 314 break; 315 } 316 } 317 318 return PLUGIN_OK; 319}