The following patch add basic Hebrew support for LyX:
When changing the document language to Hebrew (in Document Layout popup),
the text will be rendered from right-to-left
(except when entering TeX-mode)

The patch is against the cvs source (Dec 11).
I should note that this patch is very incomplete (but still usable).
Furthermore, there may be better ways to add right-to-left support
for LyX (e.g., in the patch the text rendering is still done from left
to right. It may be better to do the rendering from right to left).

If the LyX developers choose to use this patch, then I would like to
become a developer to make additional changes.
Index: src/layout.h
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/layout.h,v
retrieving revision 1.7
diff -u -r1.7 layout.h
--- src/layout.h        1999/12/07 00:44:51     1.7
+++ src/layout.h        1999/12/11 18:11:23
@@ -65,6 +65,15 @@
        MARGIN_RIGHT_ADDRESS_BOX
 };
 
+
+///
+enum LyXDirection {
+       ///
+       LYX_DIR_LEFT_TO_RIGHT,
+       ///
+       LYX_DIR_RIGHT_TO_LEFT
+};
+  
 ///
 enum LyXAlignment {
        ///
Index: src/lyxtext.h
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/lyxtext.h,v
retrieving revision 1.6
diff -u -r1.6 lyxtext.h
--- src/lyxtext.h       1999/11/22 16:19:46     1.6
+++ src/lyxtext.h       1999/12/11 18:11:28
@@ -21,6 +21,7 @@
 #include "undo.h"
 #include "lyxcursor.h"
 #include "lyxparagraph.h"
+#include "layout.h"
 
 class Buffer;
 class BufferParams;
@@ -580,6 +581,44 @@
          specified row
          */
        LyXParagraph::size_type RowLast(Row * row);
+
+       ///
+       LyXDirection GetDirection(LyXParagraph * par);
+
+       ///
+       LyXDirection GetLetterDirection(LyXParagraph * par, LyXParagraph::size_type 
+pos);
+
+       ///
+       LyXParagraph::size_type log2vis_list[1000];// Fix this!
+
+       ///
+       LyXParagraph::size_type vis2log_list[1000];
+
+       ///
+       LyXParagraph::size_type log2vis_start;
+
+       ///
+       LyXDirection log2vis_direction;
+
+
+       /// Maps positions in the visual string to positions in logical string.
+       inline LyXParagraph::size_type log2vis(LyXParagraph::size_type pos) {
+          if (log2vis_direction == LYX_DIR_LEFT_TO_RIGHT)
+             return pos;
+          else
+             return log2vis_list[pos-log2vis_start];
+       }
+
+       /// Maps positions in the logical string to positions in visual string.
+       inline LyXParagraph::size_type vis2log(LyXParagraph::size_type pos) {
+          if (log2vis_direction == LYX_DIR_LEFT_TO_RIGHT)
+             return pos;
+          else
+             return vis2log_list[pos-log2vis_start];
+       }
+
+       ///
+       void log2vis_Init(Row *row);
 };
 
 #endif
Index: src/tex-strings.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/tex-strings.C,v
retrieving revision 1.2
diff -u -r1.2 tex-strings.C
--- src/tex-strings.C   1999/11/15 12:01:38     1.2
+++ src/tex-strings.C   1999/12/11 18:11:29
@@ -56,7 +56,7 @@
                           "english", "esperanto", "estonian",
                           "finnish", "francais", "french", "frenchb",
                           "galician",
-                          "german", "greek", "hungarian", "irish",
+                          "german", "greek", "hebrew", "hungarian", "irish",
                           "italian", "lsorbian", "magyar", "norsk",
                           "polish", "portuges", "romanian",
                           "russian", "scottish",
Index: src/text.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/text.C,v
retrieving revision 1.9
diff -u -r1.9 text.C
--- src/text.C  1999/11/22 16:19:46     1.9
+++ src/text.C  1999/12/11 18:12:02
@@ -128,14 +128,77 @@
                return row->next->pos - 1;
 }
 
+LyXDirection LyXText::GetDirection(LyXParagraph *par) {
+       if (parameters->language == "hebrew" && ! par->table)
+               return LYX_DIR_RIGHT_TO_LEFT;
+       else 
+               return LYX_DIR_LEFT_TO_RIGHT;
+}
+
+LyXDirection LyXText::GetLetterDirection(LyXParagraph * par, LyXParagraph::size_type 
+pos) {
+       if (parameters->language == "hebrew" && !par->table
+           && GetFont(par, pos).latex() != LyXFont::ON)
+               return LYX_DIR_RIGHT_TO_LEFT;
+       else 
+               return LYX_DIR_LEFT_TO_RIGHT;
+}
+
+/// Should this be replaced by a full BiDi alg. ? 
+void LyXText::log2vis_Init(Row *row) {
+       log2vis_direction = GetDirection(row->par);
+       if (log2vis_direction == LYX_DIR_LEFT_TO_RIGHT)
+          return;
+
+       LyXParagraph::size_type lpos, vpos, last, swap_start = -1, swap_end = -1;
+       last = RowLast(row);
+       log2vis_start = row->pos;
+       lpos = last;
+
+       if (log2vis_start <= last &&
+           GetLetterDirection(row->par, lpos) == LYX_DIR_LEFT_TO_RIGHT) {
+               swap_end = lpos;
+               lpos--;
+               while(lpos >= log2vis_start &&
+                     GetLetterDirection(row->par, lpos) == LYX_DIR_LEFT_TO_RIGHT)
+                       lpos--;
+               lpos++;
+               swap_start = lpos;
+       }
+       for (vpos = log2vis_start; vpos <= last; vpos++) {
+          vis2log_list[vpos-log2vis_start] = lpos;
+          log2vis_list[lpos-log2vis_start] = vpos;
+          if (vpos < last)
+               if (swap_end == -1) {
+                       lpos--;
+                       if (GetLetterDirection(row->par, lpos) == 
+LYX_DIR_LEFT_TO_RIGHT) {
+                               swap_end = lpos;
+                               lpos--;
+                               while(lpos >= log2vis_start &&
+                                     GetLetterDirection(row->par, lpos) == 
+LYX_DIR_LEFT_TO_RIGHT)
+                                       lpos--;
+                               lpos++;
+                               swap_start = lpos;
+                       }
+               } else {
+                       lpos++;
+                       if (lpos > swap_end) {
+                               lpos = swap_start-1;
+                               swap_end = -1;
+                       }
+               }
+       }
+       vis2log_list[last+1-log2vis_start] = -1;
+       log2vis_list[last+1-log2vis_start] = -1;
+}
 
-void LyXText::Draw(Row * row, LyXParagraph::size_type & pos,
+void LyXText::Draw(Row * row, LyXParagraph::size_type & vpos,
                   LyXScreen & scr, int offset, float & x)
 {
+       LyXParagraph::size_type pos = vis2log(vpos);
        char c = row->par->GetChar(pos);
 
        if (IsNewlineChar(c)) {
-               ++pos;
+               ++vpos;
                // Draw end-of-line marker
 
                LyXFont font = GetFont(row->par, pos);
@@ -209,13 +272,13 @@
                scr.drawLine(gc_foot, offset + row->baseline,
                             int(tmpx), int(x - tmpx));
          
-               pos++;
+               vpos++;
                return;
        } else if (c == LyXParagraph::META_INSET) {
                Inset * tmpinset = row->par->GetInset(pos);
                if (tmpinset) 
                        tmpinset->Draw(font, scr, offset + row->baseline, x);
-               pos++;
+               vpos++;
                return;
        }
 
@@ -234,15 +297,16 @@
        // will only overflow if the machine is out of memory...
        static string textstring;
        textstring = c;
-       ++pos;
+       ++vpos;
 
        LyXParagraph::size_type last = RowLast(row);
        
-       while (pos <= last
-              && static_cast<char>(c = row->par->GetChar(pos)) > ' '
+       while (vpos <= last &&
+              (pos = vis2log(vpos)) >= 0
+              && static_cast<unsigned char>(c = row->par->GetChar(pos)) > ' '
               && font2 == GetFont(row->par, pos)) {
                textstring += c;
-               ++pos;
+               ++vpos;
        }
        float tmpx = x;
 
@@ -3207,7 +3271,8 @@
                            Row * row_ptr, long y)
 {
        /* returns a printed row */
-       LyXParagraph::size_type pos, pos_end;
+       LyXDirection direction = GetDirection(row_ptr->par);
+       LyXParagraph::size_type vpos, pos, pos_end;
        float x, tmpx;
        int y_top, y_bottom;
        float fill_separator, fill_hfill, fill_label_hfill;
@@ -3223,8 +3288,6 @@
        PrepareToPrint(row_ptr, x, fill_separator,
                       fill_hfill, fill_label_hfill);
 
-       LyXParagraph::size_type main_body = 
-               BeginningOfMainBody(row_ptr->par);
        /* initialize the pixmap */
        
        scr.fillRectangle(gc_clear,
@@ -3234,20 +3297,37 @@
                /* selection code */ 
                if (sel_start_cursor.row == row_ptr &&
                    sel_end_cursor.row == row_ptr) {
+                    if (direction == LYX_DIR_LEFT_TO_RIGHT)
                        scr.fillRectangle(gc_selection, sel_start_cursor.x,
                                          offset,
                                          sel_end_cursor.x -
                                          sel_start_cursor.x,
                                          row_ptr->height);
+                    else
+                       scr.fillRectangle(gc_selection, sel_end_cursor.x,
+                                         offset,
+                                         sel_start_cursor.x -
+                                         sel_end_cursor.x,
+                                         row_ptr->height);
                }
                else if (sel_start_cursor.row == row_ptr) {
+                    if (direction == LYX_DIR_LEFT_TO_RIGHT)
                        scr.fillRectangle(gc_selection, sel_start_cursor.x,
                                          offset,
                                          paperwidth - sel_start_cursor.x,
                                          row_ptr->height);
+                    else
+                       scr.fillRectangle(gc_selection, 0, offset,
+                                         sel_start_cursor.x, row_ptr->height);
                } else if (sel_end_cursor.row == row_ptr) {
+                    if (direction == LYX_DIR_LEFT_TO_RIGHT)
                        scr.fillRectangle(gc_selection, 0, offset,
                                          sel_end_cursor.x, row_ptr->height);
+                    else
+                       scr.fillRectangle(gc_selection, sel_end_cursor.x,
+                                         offset,
+                                         paperwidth - sel_end_cursor.x,
+                                         row_ptr->height);
                } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
                        scr.fillRectangle(gc_selection, 0, offset,
                                          paperwidth, row_ptr->height);
@@ -3549,7 +3629,8 @@
        /* draw the text in the pixmap */  
        pos_end = RowLast(row_ptr);
        
-       pos = row_ptr->pos;
+       vpos = row_ptr->pos;
+       log2vis_Init(row_ptr);
        /* table stuff -- begin*/
        if (row_ptr->par->table) {
                bool on_off;
@@ -3557,7 +3638,8 @@
                float x_old = x;
                x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
                
-               while (pos <= pos_end)  {
+               while (vpos <= pos_end)  {
+                       pos = vis2log(vpos);
                        if (row_ptr->par->IsNewline(pos)) {
                                
                                x = x_old + row_ptr->par->table->WidthOfColumn(cell);
@@ -3595,7 +3677,7 @@
                                x += 
row_ptr->par->table->GetBeginningOfTextInCell(cell);
                                if (row_ptr->par->table->IsFirstCell(cell))
                                        cell--; // little hack, sorry
-                               pos++;
+                               vpos++;
                        } else if (row_ptr->par->IsHfill(pos)) {
                                x += 1;
                                
@@ -3603,7 +3685,7 @@
                                                     offset + row_ptr->baseline - 
DefaultHeight()/2, 
                                                     offset + row_ptr->baseline);      
         
                                x += 2;
-                               pos++;
+                               vpos++;
                        } else {
                                if (row_ptr->par->IsSeparator(pos)) {
                                        tmpx = x;
@@ -3632,9 +3714,9 @@
                                                                     int(x - tmpx));   
                     
                                                }
                                        }
-                                       pos++;
+                                       vpos++;
                                } else
-                                       Draw(row_ptr, pos, scr, offset, x);
+                                       Draw(row_ptr, vpos, scr, offset, x);
                        }
                }
                
@@ -3674,9 +3756,18 @@
                }
        } else {
                /* table stuff -- end*/
-               
-               while (pos <= pos_end)  {
-                       
+               LyXParagraph::size_type vis_main_body = -1;
+               LyXParagraph::size_type main_body = 
+                       BeginningOfMainBody(row_ptr->par);
+               if (main_body > 0)
+                  vis_main_body = (direction == LYX_DIR_LEFT_TO_RIGHT) ? 
+                     log2vis(main_body) : log2vis(main_body-1);
+               if (direction == LYX_DIR_RIGHT_TO_LEFT &&
+                   pos_end >= row_ptr->pos
+                   && row_ptr->par->IsSeparator(vis2log(vpos)))
+                  x -= fill_separator;
+               while (vpos <= pos_end)  {
+                       pos = vis2log(vpos);
                        if (row_ptr->par->IsHfill(pos)) {
                                x += 1;
                                scr.drawVerticalLine(gc_fill, int(x),  
@@ -3733,15 +3824,15 @@
                                                                     int(x - tmpx));
                                                }
                                        }
-                                       pos++;
+                                       vpos++;
                                } else
-                                       Draw(row_ptr, pos, scr, offset, x);
+                                       Draw(row_ptr, vpos, scr, offset, x);
                        }
-                       if (pos == main_body) {
+                       if (vpos == vis_main_body) {
                                x += GetFont(row_ptr->par, -2).stringWidth(
                                        layout.labelsep);
-                               if (row_ptr->par->IsLineSeparator(pos - 1))
-                                       x-= SingleWidth(row_ptr->par, pos - 1);
+                               if (row_ptr->par->IsLineSeparator(main_body-1))
+                                       x-= SingleWidth(row_ptr->par, main_body-1);
                                if (x < left_margin)
                                        x = left_margin;
                        }
@@ -3793,13 +3884,18 @@
        int left_margin = LabelEnd(row);
        PrepareToPrint(row, tmpx, fill_separator,
                       fill_hfill, fill_label_hfill);
-       int main_body = BeginningOfMainBody(row->par);
-   
-       int c = row->pos;
 
-       int last = RowLast(row);
+       LyXDirection direction = GetDirection(row->par);
+       LyXParagraph::size_type vc = row->pos;
+       LyXParagraph::size_type last = RowLast(row);
+       LyXParagraph::size_type c;
+
+       log2vis_Init(row);
        if (row->par->IsNewline(last))
-               last--;
+               if (direction == LYX_DIR_LEFT_TO_RIGHT)
+                       last--;
+               else
+                       vc++;
    
        LyXLayout const & layout = textclasslist.Style(parameters->textclass,
                                           row->par->GetLayout());
@@ -3811,7 +3907,8 @@
                float x_old = tmpx;
                bool ready = false;
                tmpx += row->par->table->GetBeginningOfTextInCell(cell);
-               while (c <= last
+               while (vc <= last
+                      && (c = vis2log(vc)) >= 0
                       && tmpx + (SingleWidth(row->par, c)/2) <= x
                       && !ready){
                        if (row->par->IsNewline(c)) {
@@ -3820,22 +3917,32 @@
                                        x_old = tmpx;
                                        cell++;
                                        tmpx += 
row->par->table->GetBeginningOfTextInCell(cell);
-                                       c++;
+                                       vc++;
                                } else
                                        ready = true;
                        } else {
                                tmpx += SingleWidth(row->par, c);
-                               c++;
+                               vc++;
                        }
                }
-       } else
+       } else {
                /* table stuff -- end*/
+               LyXParagraph::size_type vis_main_body = -1;
+               LyXParagraph::size_type main_body = BeginningOfMainBody(row->par);
+               if (main_body > 0)
+                  vis_main_body = (direction == LYX_DIR_LEFT_TO_RIGHT) ? 
+                     log2vis(main_body) : log2vis(main_body-1);
+               if (direction == LYX_DIR_RIGHT_TO_LEFT  &&
+                   last >= row->pos && 
+                   row->par->IsSeparator(vis2log(row->pos)))
+                       tmpx -= fill_separator;
 
-               while (c <= last
+               while (vc <= last
+                      && (c = vis2log(vc)) >= 0
                       && tmpx + (SingleWidth(row->par, c)/2)  <= x) {
                        
-                       if (c && c == main_body
-                           && !row->par->IsLineSeparator(c - 1)) {
+                       if (vc == vis_main_body
+                           && !row->par->IsLineSeparator(main_body-1)) {
                                tmpx += GetFont(row->par, -2)
                                        .stringWidth(layout.labelsep);
                                if (tmpx < left_margin)
@@ -3853,17 +3960,22 @@
                                 && row->par->IsSeparator(c)) {
                                tmpx+= fill_separator;  
                        }
-                       c++;
-                       if (c == main_body
-                           && row->par->IsLineSeparator(c - 1)) {
+                       vc++;
+                       if (vc == vis_main_body
+                           && row->par->IsLineSeparator(main_body-1)) {
                                tmpx += GetFont(row->par, -2)
                                        .stringWidth(layout.labelsep);
-                               tmpx-= SingleWidth(row->par, c - 1);
+                               tmpx-= SingleWidth(row->par, main_body-1);
                                if (tmpx < left_margin)
                                        tmpx = left_margin;
                        }
                }
+       }
        /* make sure that a last space in a row doesnt count */
+       c = vis2log(vc);
+       if (GetLetterDirection(row->par, c) == LYX_DIR_RIGHT_TO_LEFT)
+          c++;
+
        if (c > 0 && c >= last
            && row->par->IsLineSeparator(c - 1)
            && !(!row->next || row->next->par != row->par)) {
Index: src/text2.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/text2.C,v
retrieving revision 1.12
diff -u -r1.12 text2.C
--- src/text2.C 1999/11/22 16:19:46     1.12
+++ src/text2.C 1999/12/11 18:12:29
@@ -927,7 +927,16 @@
        last_sel_cursor = cursor;
    
        /* and now the whole selection */ 
-   
+
+       if (sel_cursor.par == cursor.par)
+          if (sel_cursor.pos < cursor.pos) {
+               sel_end_cursor = cursor;
+               sel_start_cursor = sel_cursor;
+       } else {
+               sel_end_cursor = sel_cursor; 
+               sel_start_cursor = cursor;
+       }
+       else
        if (sel_cursor.y < cursor.y ||
            (sel_cursor.y == cursor.y && sel_cursor.x < cursor.x)) {
                sel_end_cursor = cursor;
@@ -2792,7 +2801,8 @@
        Row * row;
        int left_margin;
        LyXParagraph * tmppar;
-   
+       LyXParagraph::size_type vpos,cursor_vpos;
+
        /* correct the cursor position if impossible */
        if (pos > par->Last()){
                tmppar = par->ParFromPos(pos);
@@ -2826,19 +2836,25 @@
        cursor.y = y;
    
        /* now get the cursors x position */
-   
+       LyXDirection direction = GetDirection(row->par);
+       LyXParagraph::size_type last = RowLast(row);
+       log2vis_Init(row);
+       cursor_vpos = log2vis(cursor.pos);
+       if (cursor.pos <= last &&
+           GetLetterDirection(row->par, cursor.pos) == LYX_DIR_RIGHT_TO_LEFT)
+               cursor_vpos++;
+
        float x;
        float fill_separator, fill_hfill, fill_label_hfill;
        left_margin = LabelEnd(row);
        PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
-       LyXParagraph::size_type main_body =
-               BeginningOfMainBody(row->par);
        /* table stuff -- begin*/
        if (row->par->table) {
                int cell = NumberOfCell(row->par, row->pos);
                float x_old = x;
                x += row->par->table->GetBeginningOfTextInCell(cell);
-               for (pos = row->pos; pos < cursor.pos; pos++)  {
+               for (vpos = row->pos; vpos < cursor_vpos; vpos++)  {
+                       pos = vis2log(vpos);
                        if (row->par->IsNewline(pos)) {
                                x = x_old + row->par->table->WidthOfColumn(cell);
                                x_old = x;
@@ -2848,12 +2864,23 @@
                                x += SingleWidth(row->par, pos);
                        }
                }
-       } else
+       } else {
                /* table stuff -- end*/
-
-               for (pos = row->pos; pos < cursor.pos; pos++)  {
-                       if (pos && pos == main_body
-                           && !row->par->IsLineSeparator(pos - 1)) {
+               LyXParagraph::size_type vis_main_body = -1;
+               LyXParagraph::size_type main_body =
+                       BeginningOfMainBody(row->par);
+               if (main_body > 0)
+                  vis_main_body = (direction == LYX_DIR_LEFT_TO_RIGHT) ? 
+                     log2vis(main_body) : log2vis(main_body-1);
+
+               if (direction == LYX_DIR_RIGHT_TO_LEFT  &&
+                   last >= row->pos && 
+                   row->par->IsSeparator(vis2log(row->pos)))
+                       x -= fill_separator;
+               for (vpos = row->pos; vpos < cursor_vpos; vpos++)  {
+                       pos = vis2log(vpos);
+                       if (vpos == vis_main_body
+                           && !row->par->IsLineSeparator(main_body-1)) {
                                x += GetFont(row->par, -2).stringWidth(
                                                    
textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
                                if (x < left_margin)
@@ -2871,16 +2898,16 @@
                                x+= fill_separator;
                        }
       
-                       if (pos + 1 == main_body
-                           && row->par->IsLineSeparator(pos)) {
+                       if (vpos+1 == vis_main_body
+                           && row->par->IsLineSeparator(main_body-1)) {
                                x += GetFont(row->par, -2).stringWidth(
                                                    
textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
-                               if (row->par->IsLineSeparator(pos))
-                                       x -= SingleWidth(row->par, pos);
+                               x -= SingleWidth(row->par, main_body-1);
                                if (x < left_margin)
                                        x = left_margin;
                        }
                }
+       }
    
        cursor.x = int(x);
    

Reply via email to