Hi guys,

attached a patch + icon the the toolbar that implements decimal alignment in 
tables.

I wouldn't mind some feedback on the code, especially where i do some chopping 
with insets (function splitCell()), but also on the general approach.

Note that this does not use dcolumn, but rather splits the column in 2 in the 
latex output. This produces the best results (tight tables) without the 
necessity of tweaking by the user. It also works nicely with tabular*

things left to be done are lyx2lyx and bumping the file format. I think that 
we'd also like a default decimal alignment symbol in the general preferences 
(for now i hardcoded a .)

i was sort of hoping to sneak this in before 2.0. Opinions?

Ed.

Ps. Patch is not against latest trunk because i cannot connect to the internet 
with my laptop atm...
Index: lib/ui/stdtoolbars.inc
===================================================================
--- lib/ui/stdtoolbars.inc      (revision 34413)
+++ lib/ui/stdtoolbars.inc      (working copy)
@@ -153,6 +153,7 @@
                Item "Align left" "command-alternatives inset-modify tabular 
m-align-left;inset-modify tabular align-left"
                Item "Align center" "command-alternatives inset-modify tabular 
m-align-center;inset-modify tabular align-center"
                Item "Align right" "command-alternatives inset-modify tabular 
m-align-right;inset-modify tabular align-right"
+               Item "Align on decimal" "inset-modify tabular set-align-decimal 
toggle"
                Separator
                Item "Align top" "command-alternatives inset-modify tabular 
m-valign-top;inset-modify tabular valign-top"
                Item "Align middle" "command-alternatives inset-modify tabular 
m-valign-middle;inset-modify tabular valign-middle"
Index: src/frontends/qt4/GuiTabular.cpp
===================================================================
--- src/frontends/qt4/GuiTabular.cpp    (revision 34413)
+++ src/frontends/qt4/GuiTabular.cpp    (working copy)
@@ -376,6 +376,15 @@
                setParam(param_str, Tabular::UNSET_BOOKTABS);
 
        //
+       string decimalsymbol = "none";
+       if (decimalCB->isChecked()) {
+               decimalsymbol = fromqstr(decimalSymbolLE->text());
+               if (decimalsymbol.empty())
+                       decimalsymbol = "."; // default for now
+       }
+       setParam(param_str, Tabular::SET_ALIGN_DECIMAL, decimalsymbol);
+
+       //
        switch (topspaceCO->currentIndex()) {
                case 0:
                        setParam(param_str, Tabular::SET_TOP_SPACE, "none");
@@ -753,6 +762,10 @@
        }
        TableAlignCB->setCurrentIndex(tableValign);
 
+       QString const align_d = toqstr(tabular.column_info[col].align_decimal);
+       decimalCB->setChecked(!align_d.isEmpty());
+       decimalSymbolLE->setText(align_d);
+
        if (!tabular.is_long_tabular) {
                headerStatusCB->setChecked(false);
                headerBorderAboveCB->setChecked(false);
Index: src/frontends/qt4/ui/TabularUi.ui
===================================================================
--- src/frontends/qt4/ui/TabularUi.ui   (revision 34413)
+++ src/frontends/qt4/ui/TabularUi.ui   (working copy)
@@ -5,8 +5,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>374</width>
-    <height>389</height>
+    <width>378</width>
+    <height>400</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -15,7 +15,7 @@
   <property name="sizeGripEnabled" stdset="0">
    <bool>true</bool>
   </property>
-  <layout class="QGridLayout" name="_2">
+  <layout class="QGridLayout" name="gridLayout_9">
    <item row="0" column="0">
     <widget class="QTabWidget" name="TabWidget">
      <property name="toolTip">
@@ -75,7 +75,7 @@
             </item>
            </widget>
           </item>
-          <item row="0" column="2" colspan="2">
+          <item row="0" column="2">
            <spacer>
             <property name="orientation">
              <enum>Qt::Horizontal</enum>
@@ -149,7 +149,7 @@
             </item>
            </widget>
           </item>
-          <item row="2" column="2" colspan="2">
+          <item row="2" column="2">
            <spacer name="spacer">
             <property name="orientation">
              <enum>Qt::Horizontal</enum>
@@ -165,15 +165,58 @@
             </property>
            </spacer>
           </item>
-          <item row="3" column="0">
-           <widget class="QCheckBox" name="multicolumnCB">
-            <property name="toolTip">
-             <string>Merge cells of different columns</string>
-            </property>
-            <property name="text">
-             <string>&amp;Multicolumn</string>
-            </property>
-           </widget>
+          <item row="3" column="0" colspan="4">
+           <layout class="QHBoxLayout" name="horizontalLayout">
+            <item>
+             <widget class="QCheckBox" name="multicolumnCB">
+              <property name="toolTip">
+               <string>Merge cells of different columns</string>
+              </property>
+              <property name="text">
+               <string>&amp;Multicolumn</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <spacer name="horizontalSpacer">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>13</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+            <item>
+             <widget class="QCheckBox" name="decimalCB">
+              <property name="text">
+               <string>Align on decimal:</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QLineEdit" name="decimalSymbolLE">
+              <property name="enabled">
+               <bool>false</bool>
+              </property>
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="text">
+               <string/>
+              </property>
+              <property name="maxLength">
+               <number>1</number>
+              </property>
+             </widget>
+            </item>
+           </layout>
           </item>
          </layout>
         </widget>
@@ -309,19 +352,6 @@
          </property>
         </widget>
        </item>
-       <item row="4" column="1">
-        <spacer name="verticalSpacer_3">
-         <property name="orientation">
-          <enum>Qt::Vertical</enum>
-         </property>
-         <property name="sizeHint" stdset="0">
-          <size>
-           <width>20</width>
-           <height>4</height>
-          </size>
-         </property>
-        </spacer>
-       </item>
       </layout>
      </widget>
      <widget class="QWidget" name="Borders">
@@ -1462,5 +1492,38 @@
   <include location="local">qt_i18n.h</include>
  </includes>
  <resources/>
- <connections/>
+ <connections>
+  <connection>
+   <sender>decimalCB</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>decimalSymbolLE</receiver>
+   <slot>setEnabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>133</x>
+     <y>146</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>260</x>
+     <y>147</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>decimalCB</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>decimalSymbolLE</receiver>
+   <slot>setFocus()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>181</x>
+     <y>153</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>262</x>
+     <y>159</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
 </ui>
Index: src/insets/InsetTabular.cpp
===================================================================
--- src/insets/InsetTabular.cpp (revision 34413)
+++ src/insets/InsetTabular.cpp (working copy)
@@ -174,6 +174,7 @@
        { Tabular::LONGTABULAR_ALIGN_LEFT, "longtabular-align-left", false },
        { Tabular::LONGTABULAR_ALIGN_CENTER, "longtabular-align-center", false 
},
        { Tabular::LONGTABULAR_ALIGN_RIGHT, "longtabular-align-right", false },
+       { Tabular::SET_ALIGN_DECIMAL, "set-align-decimal", true },
        { Tabular::LAST_ACTION, "", false }
 };
 
@@ -502,7 +503,35 @@
 }
 
 
+InsetTableCell splitCell(InsetTableCell & head, docstring const align_d, bool 
& hassep)
+{
+       InsetTableCell tail = InsetTableCell(head);
+       tail.getText(0)->setMacrocontextPosition(
+               head.getText(0)->macrocontextPosition());
+       tail.setBuffer(head.buffer());
 
+       DocIterator dit = doc_iterator_begin(&head.buffer(), &head);
+       for (; dit; dit.forwardChar()) {
+               if (dit.inTexted() && dit.depth()==1
+                       && dit.paragraph().find(align_d, false, false, 
dit.pos())) {
+                       break;
+               }
+       }
+
+       pit_type const psize = head.paragraphs().front().size();
+
+       if (dit) {
+               head.paragraphs().front().eraseChars(dit.pos(), psize, false);
+               hassep = true;
+       }
+
+       tail.paragraphs().front().eraseChars(0, 
+               dit.pos() < psize ? dit.pos() + 1 : psize, false);
+
+       return tail;
+}
+
+
 /////////////////////////////////////////////////////////////////////
 //
 // Tabular
@@ -517,6 +546,8 @@
          multirow(Tabular::CELL_NORMAL),
          alignment(LYX_ALIGN_CENTER),
          valignment(LYX_VALIGN_TOP),
+         decimal_hoffset(0),
+         decimal_width(0),
          voffset(0),
          top_line(false),
          bottom_line(false),
@@ -537,6 +568,8 @@
          multirow(cs.multirow),
          alignment(cs.alignment),
          valignment(cs.valignment),
+         decimal_hoffset(cs.decimal_hoffset),
+         decimal_width(cs.decimal_width),
          voffset(cs.voffset),
          top_line(cs.top_line),
          bottom_line(cs.bottom_line),
@@ -564,6 +597,8 @@
        std::swap(multirow, rhs.multirow);
        std::swap(alignment, rhs.alignment);
        std::swap(valignment, rhs.valignment);
+       std::swap(decimal_hoffset, rhs.decimal_hoffset);
+       std::swap(decimal_width, rhs.decimal_width);
        std::swap(voffset, rhs.voffset);
        std::swap(top_line, rhs.top_line);
        std::swap(bottom_line, rhs.bottom_line);
@@ -910,6 +945,11 @@
 
 bool Tabular::updateColumnWidths()
 {
+       vector<int> max_dwidth(ncols(), 0);
+       for(col_type c = 0; c < ncols(); ++c)
+               for(row_type r = 0; r < nrows(); ++r)
+                       max_dwidth[c] = max(max_dwidth[c], 
cell_info[r][c].decimal_width);
+
        bool update = false;
        // for each col get max of single col cells
        for(col_type c = 0; c < ncols(); ++c) {
@@ -917,7 +957,8 @@
                for(row_type r = 0; r < nrows(); ++r) {
                        idx_type const i = cellIndex(r, c);
                        if (columnSpan(i) == 1)
-                               new_width = max(new_width, cellInfo(i).width);
+                               new_width = max(new_width, cellInfo(i).width 
+                                               + max_dwidth[c] - 
cellInfo(i).decimal_width);
                }
 
                if (column_info[c].width != new_width) {
@@ -1217,6 +1258,16 @@
                break;
        }
 
+       col_type const c = cellColumn(cell);
+       if (!isMultiColumn(cell) 
+               && !column_info[c].align_decimal.empty() 
+               && cellInfo(cell).decimal_width!=0) {
+                       int max_dhoffset = 0;
+                       for(row_type r = 0; r < row_info.size() ; ++r)
+                               max_dhoffset = max(max_dhoffset, 
cell_info[r][c].decimal_hoffset);
+                       x = WIDTH_OF_LINE + max_dhoffset - 
cellInfo(cell).decimal_hoffset;
+       }
+
        return x;
 }
 
@@ -1307,6 +1358,7 @@
                   << write_attribute("valignment", column_info[c].valignment)
                   << write_attribute("width", 
column_info[c].p_width.asString())
                   << write_attribute("special", column_info[c].align_special)
+                  << write_attribute("align_decimal", 
column_info[c].align_decimal)
                   << ">\n";
        }
        for (row_type r = 0; r < nrows(); ++r) {
@@ -1413,6 +1465,7 @@
                getTokenValue(line, "valignment", column_info[c].valignment);
                getTokenValue(line, "width", column_info[c].p_width);
                getTokenValue(line, "special", column_info[c].align_special);
+               getTokenValue(line, "align_decimal", 
column_info[c].align_decimal);
        }
 
        for (row_type i = 0; i < nrows(); ++i) {
@@ -1563,11 +1616,12 @@
 Tabular::idx_type Tabular::columnSpan(idx_type cell) const
 {
        row_type const row = cellRow(cell);
-       col_type column = cellColumn(cell) + 1;
-       while (column < ncols() && isPartOfMultiColumn(row, column))
-               ++column;
+       col_type const col = cellColumn(cell);
+       int span = 1;
+       while (col + span < ncols() && isPartOfMultiColumn(row, col + span))
+               ++span;
 
-       return column - cellColumn(cell);
+       return span;
 }
 
 
@@ -2048,8 +2102,18 @@
                || ((colright || nextcolleft) && !rightLine(cell) && 
!nextcellleft)
                || (!colright && !nextcolleft && (rightLine(cell) || 
nextcellleft))
                || (coldouble != celldouble);
+
+       ismulticol |= !column_info[c].align_decimal.empty() 
+               && cellInfo(cell).decimal_width==0;
+
+       // since decimally aligned cols = 2 latex cols
+       int latexcolspan = columnSpan(cell);
+       for(col_type col = c; col < c + columnSpan(cell); ++col)
+               if (!column_info[col].align_decimal.empty())
+                       ++latexcolspan;
+
        if (ismulticol) {
-               os << "\\multicolumn{" << columnSpan(cell) << "}{";
+               os << "\\multicolumn{" << latexcolspan << "}{";
                if (c ==0 && leftLine(cell))
                        os << '|';
                if (!cellInfo(cell).align_special.empty()) {
@@ -2360,7 +2424,22 @@
                newrp.inTableCell = (getAlignment(cell) == LYX_ALIGN_BLOCK)
                                    ? OutputParams::PLAIN
                                    : OutputParams::ALIGNED;
-               ret += inset->latex(os, newrp);
+
+               if (!isMultiColumn(cell) && 
!column_info[c].align_decimal.empty()
+                       && cellInfo(cell).decimal_width!=0) {
+                       // copy cell and split in 2
+                       InsetTableCell head = 
InsetTableCell(*cellInset(cell).get());
+                       head.getText(0)->setMacrocontextPosition(
+                               
cellInset(cell)->getText(0)->macrocontextPosition());
+                       head.setBuffer(buffer());
+                       bool hassep = false;
+                       InsetTableCell tail = splitCell(head, 
column_info[c].align_decimal, hassep);
+                       head.latex(os, newrp);
+                       os << '&';
+                       ret += tail.latex(os, newrp);
+               } else 
+                       ret += inset->latex(os, newrp);
+
                runparams.encoding = newrp.encoding;
                if (rtl)
                        os << '}';
@@ -2461,6 +2540,9 @@
                        os << '|';
                if (!column_info[c].align_special.empty()) {
                        os << column_info[c].align_special;
+               } else if (!column_info[c].align_decimal.empty()) {
+                       os << "r...@{\\extracolsep{0pt}" 
+                          << column_info[c].align_decimal << "}l";
                } else {
                        if (!column_info[c].p_width.zero()) {
                                switch (column_info[c].alignment) {
@@ -3235,6 +3317,32 @@
                        // FIXME(?): do we need a second metrics call?
                        TextMetrics const & tm = 
                                
mi.base.bv->textMetrics(tabular.cellInset(cell)->getText(0));
+
+                       // determine horiz offset because of decimal align (if 
necessary)
+                       int decimal_hoffset = 0;
+                       int decimal_width = 0;
+                       if (!tabular.column_info[c].align_decimal.empty()
+                               && !tabular.isMultiColumn(cell)) {
+                               // make a copy which we will split in 2
+                               InsetTableCell head = 
InsetTableCell(*tabular.cellInset(cell).get());
+                               head.getText(0)->setMacrocontextPosition(
+                                       
tabular.cellInset(cell)->getText(0)->macrocontextPosition());
+                               head.setBuffer(tabular.buffer());
+                               // split in 2 and calculate width of each part
+                               bool hassep = false;
+                               InsetTableCell tail = 
+                                       splitCell(head, 
tabular.column_info[c].align_decimal, hassep);
+                               Dimension dim1;
+                               head.metrics(m, dim1);
+                               decimal_hoffset = dim1.width();
+                               if (hassep) {
+                                       tail.metrics(m, dim1);
+                                       decimal_width = dim1.width();
+                               }
+                       }
+                       tabular.cell_info[r][c].decimal_hoffset = 
decimal_hoffset;
+                       tabular.cell_info[r][c].decimal_width = decimal_width;
+
                        // with LYX_VALIGN_BOTTOM the descent is relative to 
the last par
                        // = descent of text in last par + TEXT_TO_INSET_OFFSET:
                        int const lastpardes = tm.last().second->descent()
@@ -4040,6 +4148,11 @@
                        status.clear();
                        return true;
 
+               case Tabular::SET_ALIGN_DECIMAL: {
+                       Tabular::col_type col = tabular.cellColumn(cur.idx());
+                       
status.setOnOff(!tabular.column_info[col].align_decimal.empty());
+               }
+
                case Tabular::MULTICOLUMN:
                        // If a row is set as longtable caption, it must not be 
allowed
                        // to unset that this row is a multicolumn.
@@ -5245,6 +5358,20 @@
                break;
        }
 
+       case Tabular::SET_ALIGN_DECIMAL: {
+               for (col_type c = sel_col_start; c <= sel_col_end; ++c) {
+                       string ds = value;
+                       if (ds=="toggle") {
+                               if 
(tabular.column_info[c].align_decimal.empty())
+                                       ds = "."; // default for now
+                               else
+                                       ds = "";
+                       }
+                       tabular.column_info[c].align_decimal = from_ascii(ds);
+               }
+               break;
+       }
+
        // dummy stuff just to avoid warnings
        case Tabular::LAST_ACTION:
                break;
Index: src/insets/InsetTabular.h
===================================================================
--- src/insets/InsetTabular.h   (revision 34413)
+++ src/insets/InsetTabular.h   (working copy)
@@ -190,6 +190,8 @@
                ///
                LONGTABULAR_ALIGN_RIGHT,
                ///
+               SET_ALIGN_DECIMAL,
+               ///
                LAST_ACTION
        };
        ///
@@ -490,6 +492,10 @@
                LyXAlignment alignment;
                ///
                VAlignment valignment;
+               /// width of the part before the decimal
+               int decimal_hoffset;
+               /// width of the decimal part
+               int decimal_width;
                ///
                int voffset;
                ///
@@ -570,6 +576,8 @@
                Length p_width;
                ///
                docstring align_special;
+               ///
+               docstring align_decimal;
        };
        ///
        typedef std::vector<ColumnData> column_vector;
@@ -944,6 +952,9 @@
 
 std::string const featureAsString(Tabular::Feature feature);
 
+/// Split cell on decimal symbol
+InsetTableCell splitCell(InsetTableCell & head, docstring const decimal_sym, 
bool & hassep);
+
 } // namespace lyx
 
 #endif // INSET_TABULAR_H

<<attachment: tabular-feature_set-align-decimal_toggle.png>>

Reply via email to