Browse Source

Add a separated rich text module

Olivier Marty 9 years ago
parent
commit
e5b7ef4d21
6 changed files with 252 additions and 171 deletions
  1. 2 1
      Makefile
  2. 17 7
      main.c
  3. 45 160
      printer.c
  4. 2 3
      printer.h
  5. 147 0
      rich_text.c
  6. 39 0
      rich_text.h

+ 2 - 1
Makefile

@@ -1,3 +1,4 @@
+
 #
 #  Copyright (C) 2014  Olivier Marty <olivier.marty.m at gmail.com>
 #
@@ -16,7 +17,7 @@
 #  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 #
 
-SRCS=time.c parser.c printer.c main.c
+SRCS=time.c parser.c rich_text.c printer.c main.c
 CC=gcc
 CFLAGS=
 LIBS=$(shell pkg-config --cflags --libs x11) -lrt

+ 17 - 7
main.c

@@ -19,6 +19,7 @@
 #include "parser.h"
 #include "time.h"
 #include "printer.h"
+#include "rich_text.h"
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
@@ -44,7 +45,11 @@ void callbackEvent(struct printerEnv* env, int key, void* a) {
   if(key == ' ') {
     // display a message
     if(!timeIsPaused())
-      printerShow(env, "(paused - press space to resume)", 0);
+    {
+      struct richText rt = richTextParse("(paused - press space to resume)\n");
+      printerShow(env, &rt);
+      richTextFree(rt);
+    }
     else
       printerClean(*env);
     
@@ -135,38 +140,43 @@ int main(int argc, char **argv)
   penv.padding = padding;
   penv.gap = gap;
   
+  struct SubtitleLine sline;
+  struct richText rt;
+  int id = 0;
   // show a counter before start the clock
   for(i = delay; i > 0; i--)
   {
     char t[16];
-    sprintf(t, "%d...\n", i);
-    printf("%s", t);
-    printerShow(&penv, t, T_ITALIC);
+    sprintf(t, "<i>%d...</i>\n", i);
+    printf("%s\n", t);
+    rt = richTextParse(t);
+    printerShow(&penv, &rt);
     sleep(1);
+    richTextFree(rt);
   }
   printf("0 !\n");
   printerClean(penv);
   timeInitialize(-factor*shift);
   
-  struct SubtitleLine sline;
-  int id = 0;
   while(!feof(f))
   {
     id = next(f, id+1, &sline);
     if(timeInFuture(timeFactor(sline.end, factor)))
     {
+      rt = richTextParse(sline.text);
       timeSleepUntil(timeFactor(sline.begin, factor));
       
       printf("%ds\n", sline.begin.tv_sec);
       // show
       printf("%s\n", sline.text);
-      printerShow(&penv, sline.text, 0);
+      printerShow(&penv, &rt);
       
       // hide
       timeSleepUntil(timeFactor(sline.end, factor));
       // TODO manage when the next subtitle appear before
       printf("\n");
       printerClean(penv);
+      richTextFree(rt);
       manageEvent(&penv, callbackEvent, NULL);
     }
     else

+ 45 - 160
printer.c

@@ -25,26 +25,6 @@
 #include <X11/XKBlib.h>
 #include <string.h>
 
-char *strnstr(const char *s, const char *find, size_t slen)
-{
-	char c, sc;
-	size_t len;
-
-	if ((c = *find++) != '\0') {
-		len = strlen(find);
-		do {
-			do {
-				if ((sc = *s++) == '\0' || slen-- < 1)
-					return (NULL);
-			} while (sc != c);
-			if (len > slen)
-				return (NULL);
-		} while (strncmp(s, find, len) != 0);
-		s--;
-	}
-	return ((char *)s);
-}
-
 void loadFont(struct printerEnv *env, XFontStruct **font, char* fontname)
 {
   *font = XLoadQueryFont(env->d, fontname);
@@ -163,165 +143,68 @@ XFontStruct* getFont(struct printerEnv env, enum t_type flags)
   return env.fontinfo;
 }
 
-// return the width of the text drawn
-// look for i and b html tags
-// bug when there is several i (or several v) nested
-// set in rflags the flags at the end of the text
-int drawText(struct printerEnv env, char *text, int size,
-  int x, int y, enum t_type flags, enum t_type *rflags, int draw)
+int drawTextRaw(struct printerEnv env, char *text, int size, enum t_type font,
+    int *x, int *y, int draw)
 {
-  char *i = strnstr(text, "<i>", size),
-       *b = strnstr(text, "<b>", size),
-       *begin = NULL, *end = NULL;
-  int  wopentag = 0, wclosetag = 0,
-       width;
-  enum t_type nflags = flags;
-  *rflags = flags;
-  if(i != NULL && (b == NULL || i < b)) // i is the first
-  {
-    wopentag = 3;
-    begin = i;
-    end = strnstr(i, "</i>", size - (i - text));
-    nflags |= T_ITALIC;
-    if(end != NULL)
-      wclosetag = 4;
-    else
-      *rflags |= T_ITALIC;
-  }
-  else if(b != NULL) // b is the first
-  {
-    wopentag = 3;
-    begin = b;
-    end = strnstr(b, "</b>", size - (b - text));
-    nflags |= T_BOLD;
-    if(end != NULL)
-      wclosetag = 4;
-    else
-      *rflags |= T_BOLD;
-  }
-  else // no opening tag
-  {
-    if(flags & T_ITALIC) // we look for it
-      i = strnstr(text, "</i>", size);
-    if(flags & T_BOLD)
-      b = strnstr(text, "</b>", size);
-    if(i != NULL && (b == NULL || i < b))
-    {
-      wclosetag = 4;
-      begin = text;
-      end = i;
-      nflags |= T_ITALIC;
-      *rflags &= ~T_ITALIC;
-    }
-    else if(b != NULL)
-    {
-      wclosetag = 4;
-      begin = text;
-      end = b;
-      nflags |= T_BOLD;
-      *rflags &= ~T_BOLD;
-    }
-  }
-  
-  enum t_type dummy;
-  if(begin != NULL && end != NULL)
+  int font_direction, font_ascent, font_descent;
+  XCharStruct text_structure;
+  XTextExtents(getFont(env, font), text, size,
+               &font_direction, &font_ascent, &font_descent,
+               &text_structure);
+  if(draw)
   {
-    // before
-    width =  drawText(env, text, begin - text, x, y, flags, &dummy, draw);
-    // middle
-    width += drawText(env, begin + wopentag, end - begin - wopentag,
-      x + width, y, nflags, &dummy, draw);
-    // after
-    width += drawText(env, end + wclosetag, size - (end + wclosetag - begin),
-      x + width, y, flags, rflags, draw);
+    XSetFont(env.d, env.gc, getFont(env, font)->fid);
+    XDrawString(env.d, env.w, env.gc, *x, *y, text, size);
   }
-  else if(begin != NULL)
+  *x += text_structure.width;
+}
+
+int drawTextLines(struct printerEnv env, char *text, int size, enum t_type font,
+    int *x, int *y, int *maxw, int draw)
+{
+  char *nl = memchr(text, '\n', size);
+  if(nl == NULL)
   {
-    // before
-    width =  drawText(env, text, begin - text, x, y, flags, &dummy, draw);
-    // middle
-    width += drawText(env, begin + wopentag, size - (begin + wopentag - text),
-      x + width, y, nflags, &dummy, draw);
-    *rflags |= dummy;
+    drawTextRaw(env, text, size, font, x, y, draw);
+    if(*x > *maxw)
+      *maxw = *x;
   }
   else
   {
-    int font_direction, font_ascent, font_descent;
-    XCharStruct text_structure;
-    XTextExtents(getFont(env, flags), text, size,
-                 &font_direction, &font_ascent, &font_descent,
-                 &text_structure);
-    width = text_structure.width;
-    
-    if(draw)
-    {
-      XSetFont(env.d, env.gc, getFont(env, flags)->fid);
-      XDrawString(env.d, env.w, env.gc, x, y, text, size);
-    }
+    drawTextRaw(env, text, nl-text, font, x, y, draw);
+    if(*x > *maxw)
+      *maxw = *x;
+    *x = env.padding;
+    *y += env.maxascent + env.maxdescent + env.gap;
+    drawTextLines(env, nl+1, text-nl-1+size, font, x, y, maxw, draw);
   }
-  
-  return width;
 }
 
-// return a the max width
-int printLines(struct printerEnv env, char *text, int y, enum t_type flags,
-  int draw)
+// update x and y
+int drawText(struct printerEnv env, struct richText *rt,
+    int *x, int *y, int *maxw, int draw)
 {
-  char *next;
-  int size;
-  int width = 0;
-  
-  next = strchr(text, '\n');
-  if(next == NULL)
-  {
-    size = strlen(text);
-    next = text + size;
-  }
-  else
+  if(rt->left != NULL && rt->right != NULL)
   {
-    size = next-text;
-    if(*(next-1) == '\r')
-      size--; // hide this character
-    next++; // forget \n
+    drawText(env, rt->left, x, y, maxw, draw);
+    drawText(env, rt->right, x, y, maxw, draw);
   }
-  
-  // compute the size of the text
-  enum t_type dummy;
-  int tmp = drawText(env, text, size, 0, 0, flags, &dummy, 0);
-  
-  // print line
-  if(draw)
-    drawText(env, text, size, (env.width - tmp)/2, y, flags, &flags, 1);
   else
-    flags = dummy;
-  
-  // print next lines
-  if(*next != '\0')
-    width = printLines(env, next, y + env.maxascent + env.maxdescent
-      + env.gap, flags, draw);
-  
-  if(tmp > width)
-    return tmp;
-  return width;
+    drawTextLines(env, rt->pos, rt->size, rt->type, x, y, maxw, draw);
 }
 
-void printerShow(struct printerEnv *env, char* text, enum t_type font)
+void printerShow(struct printerEnv *env, struct richText *rt)
 {
-  int nlines = 1;
-  char *p = text;
+  int x, y;
   // remap the window
   XMapWindow(env->d, env->w);
-  while((p = strchr(p, '\n')) != NULL)
-  {
-    p++;
-    if(*p == '\0')
-      break;
-    nlines++;
-  }
   //  width and height
-  env->width = printLines(*env, text, 0, font, 0) + 2 * env->padding;
-  env->height = nlines * (env->maxascent + env->maxdescent + env->gap)
-    - env->gap + 2 * env->padding;
+  x = env->padding;
+  env->width = x;
+  env->height = env->padding;
+  drawText(*env, rt, &x, &env->height, &env->width, 0);
+  env->width += env->padding;
+  env->height += env->padding;
   
   XClearWindow(env->d, env->w);
   
@@ -335,7 +218,9 @@ void printerShow(struct printerEnv *env, char* text, enum t_type font)
   XSetForeground(env->d, env->gc, env->color_text);
   
   // text
-  printLines(*env, text, env->padding + env->maxascent, font, 1);
+  x = env->padding; // TODO avant c'était centré
+  y = env->padding + env->maxascent;
+  drawText(*env, rt, &x, &y, &x, 1);
   XFlush(env->d);
 }
 

+ 2 - 3
printer.h

@@ -19,6 +19,7 @@
 #ifndef H_PRINTER
 #define H_PRINTER
 
+#include "rich_text.h"
 #include <X11/Xlib.h>
 
 struct printerEnv
@@ -40,13 +41,11 @@ struct printerEnv
   unsigned long color_background, color_text;
 };
 
-enum t_type {T_ITALIC = 1, T_BOLD = 2};
-
 struct printerEnv printerOpenWindow(char *font, char *font_i, char *font_b,
   char *font_bi);
 void printerCloseWindow(struct printerEnv env);
 
-void printerShow(struct printerEnv *env, char* text, enum t_type font);
+void printerShow(struct printerEnv *env, struct richText *rt);
 void printerClean(struct printerEnv env);
 
 void manageEvent(struct printerEnv *env, void callback(struct printerEnv*,int,void*), void* callback_arg);

+ 147 - 0
rich_text.c

@@ -0,0 +1,147 @@
+/*
+  Copyright (C) 2014  Olivier Marty <olivier.marty.m at gmail.com>
+
+  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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#include "rich_text.h"
+#include <string.h>
+#include <stdlib.h>
+
+
+char *strnstr(const char *s, const char *find, size_t slen)
+{
+  char c, sc;
+  size_t len;
+
+  if ((c = *find++) != '\0') {
+    len = strlen(find);
+    do {
+      do {
+        if ((sc = *s++) == '\0' || slen-- < 1)
+          return (NULL);
+      } while (sc != c);
+      if (len > slen)
+        return (NULL);
+    } while (strncmp(s, find, len) != 0);
+    s--;
+  }
+  return ((char *)s);
+}
+
+/*char *strnstr(const char *s, const char *find, size_t slen)
+{
+  return (char*)memmem((void*)s, slen, (void*)find, strlen(find));
+}*/
+
+struct richText* newRt(struct richText *left, struct richText *right,
+  char* pos, int size, enum t_type type)
+{
+  struct richText *rt = malloc(sizeof(struct richText));
+  if(rt == NULL)
+  {
+    perror("malloc()");
+    exit(1);
+  }
+  rt->left = left;
+  rt->right = right;
+  rt->pos = pos;
+  rt->size = size;
+  rt->type = type;
+  return rt;
+}
+
+// rt must be of type data (pos and size)
+// inflate rt
+void parseAux(struct richText *rt) {
+  char *text = rt->pos;
+  int size = rt->size;
+  char *i = strnstr(text, "<i>", size),
+    *b = strnstr(text, "<b>", size);
+  char *end, *begin = NULL;
+  if(i == text || b == text) // text start with <i> or <b>
+  {
+    enum t_type type = rt->type;
+    if(i == text)
+    {
+      type |= T_ITALIC;
+      end = strnstr(text, "</i>", size); // TODO reverse for nested tags
+    }
+    else
+    {
+      type |= T_BOLD;
+      end = strnstr(text, "</b>", size);
+    }
+    if(end != NULL)
+    {
+      if(end == text + size - 4) // text end with end tag
+      {
+        // we do not create a node
+        rt->pos = text+3;
+        rt->size = end-text-3;
+        rt->type = type;
+        parseAux(rt);
+      }
+      else
+      {
+        rt->left = newRt(NULL, NULL, text+3, end-text-3, type);
+        rt->right = newRt(NULL, NULL, end+4, text+size-end-4, rt->type);
+        parseAux(rt->left);
+        parseAux(rt->right);
+      }
+    }
+    else // tags do not match
+    {
+      rt->left = newRt(NULL, NULL, text, 3, rt->type);
+      rt->right = newRt(NULL, NULL, text+3, size-3, rt->type);
+      // rt->left is not inflated
+      parseAux(rt->right);
+    }
+  }
+  else if(i != NULL || b != NULL) // there is a tag in the text
+  {
+    char *pos = i;
+    if(i == NULL || (b != NULL && b < i))
+      pos = b;
+    // pos : first tag
+    rt->left = newRt(NULL, NULL, text, pos-text, rt->type);
+    rt->right = newRt(NULL, NULL, pos, text+size-pos, rt->type);
+    parseAux(rt->right);
+  }
+}
+
+struct richText richTextParse(char* data) {
+  struct richText rt;
+  rt.left = NULL;
+  rt.right = NULL;
+  rt.pos = data;
+  rt.size = strlen(data);
+  rt.type = T_REGULAR;
+  parseAux(&rt);
+  return rt;
+}
+
+void richTextFree(struct richText rt) {
+  if(rt.left != NULL)
+  {
+    richTextFree(*rt.left);
+    free(rt.left);
+  }
+  if(rt.right != NULL)
+  {
+    richTextFree(*rt.right);
+    free(rt.right);
+  }
+}

+ 39 - 0
rich_text.h

@@ -0,0 +1,39 @@
+/*
+  Copyright (C) 2014  Olivier Marty <olivier.marty.m at gmail.com>
+
+  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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#ifndef H_RICH_TEXT
+#define H_RICH_TEXT
+
+enum t_type {T_REGULAR = 0, T_ITALIC = 1, T_BOLD = 2};
+
+struct richText
+{
+  struct richText *left; // left and right must be NULL or non-NULL at the same time
+  struct richText *right;
+
+  // it left and right are NULL :
+  enum t_type type;
+  char *pos;
+  int size;
+};
+
+// data is not copied
+struct richText richTextParse(char* data);
+void richTextFree(struct richText rt);
+
+#endif