home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / lyx-0.13.2.tar.gz / lyx-0.13.2.tar / lyx-0.13.2 / src / vspace.C < prev    next >
C/C++ Source or Header  |  1998-04-23  |  15KB  |  564 lines

  1. // -*- C++ -*-
  2. /* This file is part of
  3.  * ======================================================
  4.  * 
  5.  *           LyX, The Document Processor
  6.  *      
  7.  *        Copyright (C) 1995 Matthias Ettrich
  8.  *          Copyright (C) 1995-1998 The LyX Team.
  9.  *
  10.  *======================================================*/
  11.  
  12. #include <config.h>
  13.  
  14. #ifdef __GNUG__
  15. #pragma implementation "vspace.h"
  16. #endif
  17.  
  18. #include "lyx_main.h"
  19. #include "buffer.h"
  20. #include "vspace.h"
  21. #include "lyxrc.h"
  22. #include "lyxtext.h"
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include "BufferView.h"
  26.  
  27. extern LyXRC * lyxrc;
  28. extern BufferView *current_view;
  29.  
  30. //     $Id: vspace.C,v 1.1.1.1 1998/04/23 16:02:58 larsbj Exp $    
  31.  
  32. #if !defined(lint) && !defined(WITH_WARNINGS)
  33. static char vcid[] = "$Id: vspace.C,v 1.1.1.1 1998/04/23 16:02:58 larsbj Exp $";
  34. #endif /* lint */
  35.  
  36. /*  length units
  37.  */
  38.  
  39. static const int   num_units            = int(LyXLength::UNIT_NONE);
  40.  
  41. // I am not sure if "mu" should be possible to select (Lgb)
  42. static char const* unit_name[num_units] = { "sp", "pt", "bp", "dd",
  43.                         "mm", "pc", "cc", "cm",
  44.                         "in", "ex", "em", "mu" }; 
  45.  
  46.  
  47. LyXLength::UNIT unitFromString (LString const & data)
  48. {
  49.     int i=0;
  50.     while ((i<num_units) && (data != unit_name[i])) i++;
  51.     return (LyXLength::UNIT)i;
  52. }
  53.  
  54. /*  The following static items form a simple scanner for
  55.  *  length strings, used by isValid[Glue]Length.  See comments there.
  56.  */
  57. static float           number[4] = { 0, 0, 0, 0 };
  58. static LyXLength::UNIT unit[4]   = { LyXLength::UNIT_NONE,
  59.                      LyXLength::UNIT_NONE,
  60.                      LyXLength::UNIT_NONE,
  61.                      LyXLength::UNIT_NONE };
  62. //static int number_index, unit_index;
  63. int number_index, unit_index;
  64.  
  65. static void advance (LString& data, const int n)
  66. {
  67.     if (data.length() <= n)
  68.         data.erase();
  69.     else
  70.         data.substring (n, data.length()-1);
  71. }
  72.  
  73. static bool isEndOfData (LString& data)
  74. {
  75.     data.frontStrip (' ');
  76.     return data.empty();
  77. }
  78.  
  79. static char nextToken (LString& data)
  80. {
  81.     data.frontStrip (' ');
  82.  
  83.     if (data.empty())
  84.         return '\0';
  85.     else if (data[0] == '+') {
  86.         advance (data, 1);
  87.         return '+';
  88.     }
  89.     else if (data.prefixIs ("plus")) {
  90.         advance (data, 4);
  91.         return '+';
  92.     }
  93.     else if (data[0] == '-') {
  94.         advance (data, 1);
  95.         return '-';
  96.     }
  97.         else if (data.prefixIs ("minus")) {
  98.         advance (data, 5);
  99.         return '-';
  100.     }
  101.     else {
  102.         int      i;
  103.  
  104.         // I really mean assignment ("=") below, not equality!
  105.  
  106.         if ((i = strspn (data.c_str(), "0123456789."))) {
  107.             if (number_index > 3) return 'E';  // Error
  108.                         LString buffer = data; buffer.substring (0, i-1);
  109.             if (sscanf (buffer.c_str(),
  110.                     "%f", &number[number_index]) == 1) {
  111.                 advance (data, i);
  112.                 number_index++;
  113.                 return 'n';
  114.             } else 
  115.                 return 'E';  // Error
  116.         } else if ((i = strspn (data.c_str(),
  117.                        "abcdefghijklmnopqrstuvwxyz"))) {
  118.             if (unit_index > 3) return 'E';  // Error
  119.             LString buffer = data; buffer.substring (0, i-1);
  120.             unit[unit_index] = unitFromString (buffer);
  121.             if (unit[unit_index] != LyXLength::UNIT_NONE) {
  122.                 advance (data, i);
  123.                 unit_index++;
  124.                 return 'u';
  125.             } else
  126.                 return 'E';  // Error
  127.         } else
  128.             return 'E';  // Error
  129.     }
  130. }
  131.  
  132. static struct {
  133.     char const* pattern;
  134.     int   plus_val_index, minus_val_index,
  135.           plus_uni_index, minus_uni_index;
  136. } table[] = { { "nu",       0, 0, 0, 0 },
  137.           { "nu+nu",    2, 0, 2, 0 },
  138.           { "nu+nu-nu", 2, 3, 2, 3 },
  139.           { "nu+-nu",   2, 2, 2, 2 },
  140.           { "nu-nu",    0, 2, 0, 2 },
  141.           { "nu-nu+nu", 3, 2, 3, 2 },
  142.           { "nu-+nu",   2, 2, 2, 2 },
  143.           { "n+nu",     2, 0, 1, 0 },
  144.           { "n+n-nu",   2, 3, 1, 1 },
  145.           { "n+-nu",    2, 2, 1, 1 },
  146.           { "n-nu",     0, 2, 0, 1 },
  147.           { "n-n+nu",   3, 2, 1, 1 },
  148.           { "n-+nu",    2, 2, 1, 1 },
  149.               { "",         0, 0, 0, 0 }   // sentinel, must be empty
  150. };
  151.  
  152. bool isValidGlueLength (LString const & data, LyXGlueLength* result)
  153. {
  154.     // This parser is table-driven.  First, it constructs a "pattern"
  155.         // that describes the sequence of tokens in "data".  For example,
  156.     // "n-nu" means: number, minus sign, number, unit.  As we go along,
  157.         // numbers and units are stored into static arrays.  Then, "pattern"
  158.         // is searched in the "table".  If it is found, the associated
  159.         // table entries tell us which number and unit should go where
  160.         // in the LyXLength structure.  Example: if "data" has the "pattern"
  161.         // "nu+nu-nu", the associated table entries are "2, 3, 2, 3".  
  162.     // That means, "plus_val" is the second number that was seen
  163.     // in the input, "minus_val" is the third number, and "plus_uni"
  164.     // and "minus_uni" are the second and third units, respectively.
  165.     // ("val" and "uni" are always the first items seen in "data".)
  166.         //     This is the most elegant solution I could find -- a straight-
  167.         // forward approach leads to very long, tedious code that would be
  168.         // much harder to understand and maintain. (AS)
  169.  
  170.  
  171.         LString   buffer = data;
  172.     int       pattern_index = 0, table_index = 0;
  173.     char      pattern[20];
  174.  
  175.     number_index = unit_index = 1;  // entries at index 0 are sentinels
  176.  
  177.     // construct "pattern" from "data"
  178.     while (!isEndOfData (buffer)) {
  179.         if (pattern_index > 20) return false;
  180.         pattern[pattern_index] = nextToken (buffer);
  181.         if (pattern[pattern_index] == 'E') return false;
  182.         pattern_index++;
  183.     }
  184.     pattern[pattern_index] = '\0';
  185.  
  186.     // search "pattern" in "table"
  187.     table_index = 0;
  188.     while (strcmp (pattern, table[table_index].pattern)) {
  189.         table_index++;
  190.         if (!*table[table_index].pattern) return false;
  191.     }
  192.     
  193.     // Get the values from the appropriate places.  If an index
  194.     // is zero, the corresponding array value is zero or UNIT_NONE,
  195.     // so we needn't check this.
  196.     if (result) {
  197.         result->val = number[1];
  198.         result->uni = unit[1];
  199.         result->plus_val  = number[table[table_index].plus_val_index];
  200.         result->minus_val = number[table[table_index].minus_val_index];
  201.         result->plus_uni  = unit  [table[table_index].plus_uni_index];
  202.         result->minus_uni = unit  [table[table_index].minus_uni_index];
  203.     }
  204.     return true;
  205. }
  206.  
  207.  
  208. bool isValidLength(LString const & data, LyXLength* result)
  209. {
  210.     /// This is a trimmed down version of isValidGlueLength.
  211.     /// The parser may seem overkill for lengths without 
  212.     /// glue, but since we already have it, using it is
  213.     /// easier than writing something from scratch.
  214.  
  215.         LString   buffer = data;
  216.     int       pattern_index = 0;
  217.     char      pattern[3];
  218.  
  219.     number_index = unit_index = 1;  // entries at index 0 are sentinels
  220.  
  221.     // construct "pattern" from "data"
  222.     while (!isEndOfData (buffer)) {
  223.         if (pattern_index > 2) return false;
  224.         pattern[pattern_index] = nextToken (buffer);
  225.         if (pattern[pattern_index] == 'E') return false;
  226.         pattern_index++;
  227.     }
  228.     pattern[pattern_index] = '\0';
  229.  
  230.     // only the most basic pattern is accepted here
  231.     if (strcmp (pattern, "nu") != 0) return false;        
  232.     
  233.     // It _was_ a correct length string.  
  234.     // Store away the values we found.
  235.     if (result) {
  236.         result->val = number[1];
  237.         result->uni = unit[1];
  238.     }
  239.     return true;
  240. }
  241.  
  242. /// LyXLength class
  243.  
  244. LyXLength::LyXLength(LString const & data)
  245. {
  246.     LyXLength tmp;
  247.     
  248.     if (!isValidLength (data, &tmp))
  249.         return; // should raise an exception
  250.     else {
  251.         val = tmp.val;
  252.         uni = tmp.uni;
  253.     }
  254. }
  255.  
  256. bool LyXLength::operator== (LyXLength other)
  257. {
  258.     return (this->val == other.val)
  259.         && (this->uni == other.uni);
  260. }
  261.  
  262. LString LyXLength::asString() const
  263. {
  264.     char buffer[20];
  265.  
  266.     sprintf (buffer, "%g%s", val, unit_name[uni]);
  267.     return LString (buffer);
  268. }
  269.  
  270.  
  271. /*  LyXGlueLength class
  272.  */
  273.  
  274. LyXGlueLength::LyXGlueLength (LString const & data)
  275. {
  276.     LyXGlueLength tmp(0.0, PT);
  277.  
  278.     if (!isValidGlueLength (data, &tmp))
  279.         return; // should raise an exception
  280.     else {
  281.         val=tmp.val;
  282.         uni=tmp.uni;
  283.         plus_val =tmp.plus_val;
  284.         plus_uni =tmp.plus_uni;
  285.         minus_val=tmp.minus_val;
  286.         minus_uni=tmp.minus_uni;
  287.     }
  288. }
  289.  
  290.  
  291. bool LyXGlueLength::operator== (LyXGlueLength other)
  292. {
  293.     return (this->val == other.val) 
  294.         && (this->uni == other.uni)
  295.         && (this->plus_val  == other.plus_val)
  296.         && (this->plus_uni  == other.plus_uni)
  297.         && (this->minus_val == other.minus_val)
  298.         && (this->minus_uni == other.minus_uni);
  299. }
  300.  
  301.  
  302. LString LyXGlueLength::asString () const
  303. {
  304.     char buffer[20];
  305.     
  306.     if (plus_val != 0.0)
  307.         if (minus_val != 0.0)
  308.         if ((uni == plus_uni) && (uni == minus_uni))
  309.             if (plus_val == minus_val)
  310.             sprintf (buffer, "%g+-%g%s",
  311.                  val, plus_val, unit_name[uni]);
  312.             else
  313.             sprintf (buffer, "%g+%g-%g%s",
  314.                  val, plus_val, minus_val, 
  315.                  unit_name[uni]);
  316.         else
  317.             if ((plus_uni == minus_uni) && (plus_val == minus_val))
  318.             sprintf (buffer, "%g%s+-%g%s",
  319.                  val, unit_name[uni],
  320.                  plus_val, unit_name[plus_uni]);
  321.             else
  322.             sprintf (buffer, "%g%s+%g%s-%g%s",
  323.                  val,       unit_name[uni],
  324.                  plus_val,  unit_name[plus_uni],
  325.                  minus_val, unit_name[minus_uni]);
  326.         else 
  327.         if (uni == plus_uni)
  328.             sprintf (buffer, "%g+%g%s",
  329.                  val, plus_val, unit_name[uni]);
  330.         else
  331.             sprintf (buffer, "%g%s+%g%s",
  332.                  val,      unit_name[uni],
  333.                  plus_val, unit_name[plus_uni]);
  334.     else
  335.         if (minus_val != 0.0)
  336.         if (uni == minus_uni)
  337.             sprintf (buffer, "%g-%g%s",
  338.                  val, minus_val, unit_name[uni]);
  339.         else
  340.             sprintf (buffer, "%g%s-%g%s",
  341.                  val,       unit_name[uni],
  342.                  minus_val, unit_name[minus_uni]);
  343.         else
  344.         sprintf (buffer, "%g%s", val, unit_name[uni]);
  345.     return LString (buffer);
  346. }
  347.  
  348.  
  349. LString LyXGlueLength::asLatexString() const
  350. {
  351.     char buffer[40];
  352.  
  353.     if (plus_val != 0.0)
  354.         if (minus_val != 0.0)
  355.             sprintf (buffer, "%g%s plus %g%s minus %g%s",
  356.                  val, unit_name[uni],
  357.                  plus_val,  unit_name[plus_uni],
  358.                  minus_val, unit_name[minus_uni]);
  359.         else
  360.             sprintf (buffer, "%g%s plus %g%s",
  361.                  val,      unit_name[uni],
  362.                  plus_val, unit_name[plus_uni]);
  363.     else
  364.         if (minus_val != 0.0)
  365.             sprintf (buffer, "%g%s minus %g%s",
  366.                  val,       unit_name[uni],
  367.                  minus_val, unit_name[minus_uni]);
  368.         else
  369.             sprintf (buffer, "%g%s",
  370.                  val, unit_name[uni]);
  371.     return LString (buffer);
  372. }
  373.  
  374.  
  375. /*  VSpace class
  376.  */
  377.  
  378. VSpace::VSpace (LString const & data)
  379.     : kin (NONE), len (0.0, LyXLength::PT) 
  380. {
  381.     float   value;
  382.     LString input  = data;
  383.  
  384.     input.strip(' ');
  385.     int length = input.length();
  386.  
  387.     if (input[length-1] == '*') {
  388.         kp = true;
  389.         input.substring (0, length-2);
  390.     } else
  391.         kp = false;
  392.  
  393.     if      (input.prefixIs ("defskip"))   kin = DEFSKIP;
  394.     else if (input.prefixIs ("smallskip")) kin = SMALLSKIP;
  395.     else if (input.prefixIs ("medskip"))   kin = MEDSKIP;
  396.     else if (input.prefixIs ("bigskip"))   kin = BIGSKIP;
  397.     else if (input.prefixIs ("vfill"))     kin = VFILL;
  398.     else if (isValidGlueLength (input, &len))
  399.         kin = LENGTH;
  400.     else if (sscanf (input.c_str(), "%f", &value) == 1) {
  401.         // This last one is for reading old .lyx files
  402.         // without units in added_space_top/bottom.
  403.         // Let unit default to centimeters here.
  404.         kin = LENGTH;
  405.         len = LyXGlueLength (value, LyXLength::CM);
  406.     }
  407. }
  408.  
  409.  
  410. bool VSpace::operator== (VSpace other)
  411. {
  412.     if (this->kin == other.kin) 
  413.         if (this->kin == LENGTH)
  414.             if (this->len == other.len)
  415.                 return this->kp == other.kp;
  416.             else
  417.                 return false;
  418.         else
  419.             return this->kp == other.kp;
  420.     else
  421.         return false;
  422. }
  423.  
  424.  
  425. LString VSpace::asLyXCommand() const
  426. {
  427.         LString result;
  428.  
  429.     switch (kin) {
  430.     case NONE:      break;
  431.     case DEFSKIP:   result = "defskip";      break;
  432.     case SMALLSKIP: result = "smallskip";    break;
  433.     case MEDSKIP:   result = "medskip";      break;
  434.     case BIGSKIP:   result = "bigskip";      break;
  435.     case VFILL:     result = "vfill";        break;
  436.     case LENGTH:    result = len.asString(); break;
  437.     }
  438.     if (kp && (kin != NONE) && (kin != DEFSKIP))
  439.         return result += '*';
  440.     else
  441.         return result;
  442. }
  443.  
  444.  
  445. LString VSpace::asLatexCommand() const
  446. {
  447.     switch (kin) {
  448.     case NONE:      return LString();
  449.     case DEFSKIP:   
  450.       return current_view->currentBuffer()->params.getDefSkip().asLatexCommand();
  451.     case SMALLSKIP: return kp ? "\\vspace*{smallskipamount}"
  452.                   : "\\smallskip{}";
  453.     case MEDSKIP:   return kp ? "\\vspace*{medskipamount}"
  454.                   : "\\medskip{}";
  455.     case BIGSKIP:   return kp ? "\\vspace*{bigskipamount}"
  456.                   : "\\bigskip{}";
  457.     case VFILL:     return kp ? "\\vspace*{\\fill}"
  458.                   : "\\vfill{}";
  459.     case LENGTH:    return kp ? "\\vspace*{" + len.asLatexString() + '}'
  460.                   : "\\vspace{" + len.asLatexString() + '}';
  461.     }
  462.     return LString();  // should never be reached
  463. }
  464.  
  465.  
  466. int VSpace::inPixels() const
  467. {
  468.     // Height of a normal line in pixels (zoom factor considered)
  469.     int height = current_view->currentBuffer()->text->DefaultHeight(); // [pixels]
  470.  
  471.     // Zoom factor specified by user in percent
  472.     float const zoom = lyxrc->zoom / 100.0; // [percent]
  473.  
  474.     // DPI setting for monitor: pixels/inch
  475.     float const dpi = lyxrc->dpi; // screen resolution [pixels/inch]
  476.  
  477.     // We want the result in pixels
  478.     float result, value;
  479.  
  480.     switch (kin) {
  481.     case NONE: return 0;
  482.  
  483.     case DEFSKIP:
  484.       return current_view->currentBuffer()->params.getDefSkip().inPixels();
  485.  
  486.     // This is how the skips are normally defined by
  487.     // LateX.  But there should be some way to change
  488.     // this per document.
  489.     case SMALLSKIP: return height/4;
  490.     case MEDSKIP:   return height/2;
  491.     case BIGSKIP:   return height;
  492.     case VFILL:     return 3*height;
  493.                 // leave space for the vfill symbol
  494.     case LENGTH:
  495.         // Pixel values are scaled so that the ratio
  496.         // between lengths and font sizes on the screen
  497.         // is the same as on paper.
  498.         result = 0.0, value = len.value();
  499.         switch (len.unit()) {
  500.         case LyXLength::SP:
  501.             // Scaled point: sp = 1/65536 pt
  502.             result = zoom * dpi * value
  503.                 / (72.27 * 65536); // 4736286.7
  504.             break;
  505.         case LyXLength::PT:
  506.             // Point: 1 pt = 1/72.27 inch
  507.             result = zoom * dpi * value
  508.                 / 72.27; // 72.27
  509.             break;
  510.         case LyXLength::BP:
  511.             // Big point: 1 bp = 1/72 inch
  512.             result = zoom * dpi * value
  513.                 / 72; // 72
  514.             break;
  515.         case LyXLength::DD:
  516.             // Didot: 1157dd = 1238 pt?
  517.             result = zoom * dpi * value
  518.                 / (72.27/(0.376 * 2.845)); // 67.559735
  519.             break;
  520.         case LyXLength::MM:
  521.             // Millimeter: 1 mm = 1/25.4 inch
  522.             result = zoom * dpi * value
  523.                 / 25.4; // 25.4
  524.             break;
  525.         case LyXLength::PC:
  526.             // Pica: 1 pc = 12 pt
  527.             result = zoom * dpi * value
  528.                 / (72.27/12); // 6.0225
  529.             break;
  530.         case LyXLength::CC:
  531.             // Cicero: 1 cc = 12 dd
  532.             result = zoom * dpi * value
  533.                 / (72.27/ (12*0.376*2.845)); // 5.6299779
  534.             break;
  535.         case LyXLength::CM:
  536.             // Centimeter: 1 cm = 1/2.54 inch
  537.             result = zoom * dpi * value
  538.                 / 2.54; // 2.54
  539.             break;
  540.         case LyXLength::IN:
  541.             // Inch
  542.             result = zoom * dpi * value;
  543.             break;
  544.         case LyXLength::EX:
  545.             // Ex: The height of an "x"
  546.             result = zoom * value * height / 2; // what to / width?
  547.             break;
  548.         case LyXLength::EM: // what to / width?
  549.             // Em: The width of an "m"
  550.             result = zoom * value * height / 2; // Why 2?
  551.             break;
  552.         case LyXLength::MU: // This is probably only allowed in
  553.                         // math mode
  554.             result = zoom * value * height;
  555.             break;
  556.         case LyXLength::UNIT_NONE:
  557.             result = 0;  // this cannot happen
  558.             break;  
  559.         }
  560.         return int (result+0.5);
  561.     }
  562.     return 0; // never reached
  563. }
  564.