]> git.lyx.org Git - lyx.git/blob - src/insets/insettabular.C
So now we have a TabularLayoutMenu for inset-tabulars too!
[lyx.git] / src / insets / insettabular.C
1 /* This file is part of
2  * ======================================================
3  * 
4  *           LyX, The Document Processor
5  *
6  *           Copyright 2000 The LyX Team.
7  *
8  *======================================================
9  */
10
11 #include <config.h>
12
13 #include <fstream>
14 #include <algorithm>
15
16 #include <cstdlib>
17
18 #ifdef __GNUG__
19 #pragma implementation
20 #endif
21
22 #include "insettabular.h"
23
24 #include "buffer.h"
25 #include "commandtags.h"
26 #include "LaTeXFeatures.h"
27 #include "Painter.h"
28 #include "font.h"
29 #include "lyxtext.h"
30 #include "lyx_gui_misc.h"
31 #include "LyXView.h"
32 #include "lyxfunc.h"
33 #include "insets/insettext.h"
34
35 extern bool MenuLayoutTable(int);
36
37 const int ADD_TO_HEIGHT = 2;
38 const int ADD_TO_TABULAR_WIDTH = 2;
39
40 using std::ostream;
41 using std::ifstream;
42 using std::max;
43 using std::endl;
44
45
46 InsetTabular::InsetTabular(Buffer * buf, int rows, int columns)
47 {
48     if (rows <= 0)
49         rows = 1;
50     if (columns <= 0)
51         columns = 1;
52     tabular = new LyXTabular(rows,columns,buf);
53     // for now make it always display as display() inset
54     // just for test!!!
55     tabular->SetLongTabular(true);
56     the_locking_inset = 0;
57     buffer = buf;
58     cursor_visible = false;
59     cursor.x_fix = -1;
60     actcell = cursor.pos = sel_pos_start = sel_pos_end = 0;
61     no_selection = false;
62     init = true;
63 }
64
65
66 InsetTabular::InsetTabular(InsetTabular const & tab, Buffer * buf)
67 {
68     tabular = new LyXTabular(*(tab.tabular), buf);
69     the_locking_inset = 0;
70     buffer = buf;
71     cursor_visible = false;
72     cursor.x_fix = -1;
73     actcell = cursor.pos = sel_pos_start = sel_pos_end = 0;
74     no_selection = false;
75     init = true;
76 }
77
78
79 InsetTabular::~InsetTabular()
80 {
81     delete tabular;
82 }
83
84
85 Inset * InsetTabular::Clone() const
86 {
87     InsetTabular * t = new InsetTabular(*this, buffer);
88     return t;
89 }
90
91
92 void InsetTabular::Write(ostream & os) const
93 {
94     os << " Tabular" << endl;
95     tabular->Write(os);
96 }
97
98
99 void InsetTabular::Read(LyXLex & lex)
100 {
101 //    bool old_format = (lex.GetString() == "\\LyXTable");
102     string token;
103
104     if (tabular)
105         delete tabular;
106     tabular = new LyXTabular(lex, buffer);
107
108     lex.nextToken();
109     token = lex.GetString();
110     while (lex.IsOK() && (token != "\\end_inset")) {
111         lex.nextToken();
112         token = lex.GetString();
113     }
114     if (token != "\\end_inset") {
115         lex.printError("Missing \\end_inset at this point. "
116                        "Read: `$$Token'");
117     }
118     tabular->SetLongTabular(true);
119     init = true;
120 }
121
122
123 int InsetTabular::ascent(Painter & pain, LyXFont const & font) const
124 {
125     if (init) {
126         calculate_width_of_cells(pain, font);
127         init = false;
128     }
129     return tabular->GetAscentOfRow(0);
130 }
131
132
133 int InsetTabular::descent(Painter & pain, LyXFont const & font) const
134 {
135     if (init) {
136         calculate_width_of_cells(pain, font);
137         init = false;
138     }
139     return tabular->GetHeightOfTabular() - tabular->GetAscentOfRow(0);
140 }
141
142
143 int InsetTabular::width(Painter & pain, LyXFont const & font) const
144 {
145     if (init) {
146         calculate_width_of_cells(pain, font);
147         init = false;
148     }
149     return tabular->GetWidthOfTabular() + (2 * ADD_TO_TABULAR_WIDTH);
150 }
151
152
153 void InsetTabular::draw(Painter & pain, const LyXFont & font, int baseline,
154                         float & x) const
155 {
156     int i, j, cell=0;
157     int nx;
158     float cx;
159
160     UpdatableInset::draw(pain,font,baseline,x);
161     if ((top_x != int(x)) || (top_baseline != baseline)) {
162         top_x = int(x);
163         top_baseline = baseline;
164         resetPos(pain);
165     }
166     for(i=0;i<tabular->rows();++i) {
167         nx = int(x);
168         for(j=0;j<tabular->columns();++j) {
169             cx = nx + tabular->GetBeginningOfTextInCell(cell);
170             tabular->GetCellInset(cell)->draw(pain, font, baseline, cx);
171             DrawCellLines(pain, nx, baseline, i, cell);
172             nx += tabular->GetWidthOfColumn(cell);
173             ++cell;
174         }
175         baseline += tabular->GetDescentOfRow(i) + tabular->GetAscentOfRow(i+1)
176             + tabular->GetAdditionalHeight(cell+1);
177     }
178 }
179
180
181 void InsetTabular::DrawCellLines(Painter & pain, int x, int baseline,
182                                  int row, int cell) const
183 {
184     int  x2 = x + tabular->GetWidthOfColumn(cell);
185     bool on_off;
186
187     if (!tabular->TopAlreadyDrawed(cell)) {
188         on_off = !tabular->TopLine(cell);
189         pain.line(x, baseline - tabular->GetAscentOfRow(row),
190                   x2, baseline -  tabular->GetAscentOfRow(row),
191                   on_off ? LColor::tabularonoffline:LColor::tabularline,
192                   on_off ? Painter::line_onoffdash:Painter::line_solid);
193     }
194     on_off = !tabular->BottomLine(cell);
195     pain.line(x,baseline +  tabular->GetDescentOfRow(row),
196               x2, baseline +  tabular->GetDescentOfRow(row),
197               on_off ? LColor::tabularonoffline:LColor::tabularline,
198               on_off ? Painter::line_onoffdash:Painter::line_solid);
199     if (!tabular->LeftAlreadyDrawed(cell)) {
200         on_off = !tabular->LeftLine(cell);
201         pain.line(x, baseline -  tabular->GetAscentOfRow(row),
202                   x, baseline +  tabular->GetDescentOfRow(row),
203                   on_off ? LColor::tabularonoffline:LColor::tabularline,
204                   on_off ? Painter::line_onoffdash:Painter::line_solid);
205     }
206     on_off = !tabular->RightLine(cell);
207     pain.line(x2 - tabular->GetAdditionalWidth(cell),
208               baseline -  tabular->GetAscentOfRow(row),
209               x2 - tabular->GetAdditionalWidth(cell),
210               baseline +  tabular->GetDescentOfRow(row),
211               on_off ? LColor::tabularonoffline:LColor::tabularline,
212               on_off ? Painter::line_onoffdash:Painter::line_solid);
213 }
214
215
216 char const * InsetTabular::EditMessage() const
217 {
218     return _("Opened Tabular Inset");
219 }
220
221
222 void InsetTabular::Edit(BufferView * bv, int x, int y, unsigned int button)
223 {
224     UpdatableInset::Edit(bv, x, y, button);
225
226     if (!bv->lockInset(this)) {
227         lyxerr[Debug::INSETS] << "InsetTabular::Cannot lock inset" << endl;
228         return;
229     }
230     the_locking_inset = 0;
231     sel_pos_start = sel_pos_end = inset_pos = inset_x = inset_y = 0;
232     setPos(bv->painter(), x, y);
233     sel_pos_start = sel_pos_end = cursor.pos;
234     bv->text->FinishUndo();
235     if (InsetHit(bv, x, y)) {
236         ActivateCellInset(bv, x, y, button);
237     }
238     UpdateLocal(bv, true);
239 //    bv->getOwner()->getPopups().updateFormTabular();
240 }
241
242
243 void InsetTabular::InsetUnlock(BufferView * bv)
244 {
245     if (the_locking_inset) {
246         the_locking_inset->InsetUnlock(bv);
247         the_locking_inset = 0;
248     }
249     HideInsetCursor(bv);
250     if (hasCharSelection()) {
251         sel_pos_start = sel_pos_end = cursor.pos;
252         UpdateLocal(bv, false);
253     } else
254         sel_pos_start = sel_pos_end = cursor.pos;
255     no_selection = false;
256 }
257
258 void InsetTabular::UpdateLocal(BufferView * bv, bool flag)
259 {
260     if (flag) {
261         calculate_width_of_cells(bv->painter(), LyXFont(LyXFont::ALL_SANE));
262         resetPos(bv->painter());
263     }
264     bv->updateInset(this, flag);
265 }
266
267 bool InsetTabular::LockInsetInInset(BufferView * bv, UpdatableInset * inset)
268 {
269     lyxerr[Debug::INSETS] << "InsetTabular::LockInsetInInset(" <<inset<< "): ";
270     if (!inset)
271         return false;
272     if (inset == tabular->GetCellInset(actcell)) {
273         lyxerr[Debug::INSETS] << "OK" << endl;
274         the_locking_inset = tabular->GetCellInset(actcell);
275         resetPos(bv->painter());
276         inset_x = cursor.x - top_x + tabular->GetBeginningOfTextInCell(actcell);
277         inset_y = cursor.y;
278         inset_pos = cursor.pos;
279         return true;
280     } else if (the_locking_inset && (the_locking_inset == inset)) {
281         if (cursor.pos == inset_pos) {
282             lyxerr[Debug::INSETS] << "OK" << endl;
283             resetPos(bv->painter());
284             inset_x = cursor.x - top_x + tabular->GetBeginningOfTextInCell(actcell);
285             inset_y = cursor.y;
286         } else {
287             lyxerr[Debug::INSETS] << "cursor.pos != inset_pos" << endl;
288         }
289     } else if (the_locking_inset) {
290         lyxerr[Debug::INSETS] << "MAYBE" << endl;
291         return the_locking_inset->LockInsetInInset(bv, inset);
292     }
293     lyxerr[Debug::INSETS] << "NOT OK" << endl;
294     return false;
295 }
296
297 bool InsetTabular::UnlockInsetInInset(BufferView * bv, UpdatableInset * inset,
298                                    bool lr)
299 {
300     if (!the_locking_inset)
301         return false;
302     if (the_locking_inset == inset) {
303         the_locking_inset->InsetUnlock(bv);
304         the_locking_inset = 0;
305         if (lr)
306             moveRight(bv, false);
307         return true;
308     }
309     return the_locking_inset->UnlockInsetInInset(bv, inset, lr);
310 }
311
312 bool InsetTabular::UpdateInsetInInset(BufferView * bv, Inset * inset)
313 {
314     if (!the_locking_inset)
315         return false;
316     if (the_locking_inset != inset)
317         return the_locking_inset->UpdateInsetInInset(bv, inset);
318     UpdateLocal(bv);
319     return true;
320 }
321
322
323 int InsetTabular::InsetInInsetY()
324 {
325     if (!the_locking_inset)
326         return 0;
327
328     return (inset_y + the_locking_inset->InsetInInsetY());
329 }
330
331 void InsetTabular::InsetButtonRelease(BufferView * bv,
332                                       int x, int y, int button)
333 {
334     if (button == 3) {
335         LocalDispatch(bv, LFUN_LAYOUT_TABLE, "true");
336         return;
337     }
338     if (the_locking_inset) {
339         the_locking_inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button);
340         return;
341     }
342     no_selection = false;
343 }
344
345
346 void InsetTabular::InsetButtonPress(BufferView * bv, int x, int y, int button)
347 {
348     if (hasCharSelection()) {
349         sel_pos_start = sel_pos_end = 0;
350         UpdateLocal(bv, false);
351     }
352     no_selection = false;
353
354     int oldcell = actcell;
355
356     setPos(bv->painter(), x, y);
357
358     bool inset_hit = InsetHit(bv, x, y);
359
360     if ((oldcell == actcell) && the_locking_inset && inset_hit) {
361         the_locking_inset->InsetButtonPress(bv, x-inset_x, y-inset_y, button);
362         return;
363     } else if (the_locking_inset) {
364         the_locking_inset->InsetUnlock(bv);
365     }
366     the_locking_inset = 0;
367     sel_pos_start = sel_pos_end = cursor.pos;
368     sel_cell_start = sel_cell_end = actcell;
369     if (inset_hit && bv->the_locking_inset) {
370         ActivateCellInset(bv, x, y, button);
371         the_locking_inset->InsetButtonPress(bv, x-inset_x, y-inset_y, button);
372     }
373     
374 #if 0
375     if (button == 3)
376         bview->getOwner()->getPopups().showFormTabular();
377     else if (oldcell != actcell)
378         bview->getOwner()->getPopups().updateFormTabular();
379 #endif
380 }
381
382
383 void InsetTabular::InsetMotionNotify(BufferView * bv, int x, int y, int button)
384 {
385     if (the_locking_inset) {
386         the_locking_inset->InsetMotionNotify(bv, x - inset_x,
387                                              y - inset_y, button);
388         return;
389     }
390     if (!no_selection) {
391             // int oldcell = actcell,
392             int old = sel_pos_end;
393
394         setPos(bv->painter(), x, y);
395         sel_pos_end = cursor.pos;
396         sel_cell_end = actcell;
397         if (old != sel_pos_end)
398             UpdateLocal(bv, false);
399 #if 0
400         if (oldcell != actcell)
401             bview->getOwner()->getPopups().updateFormTabular();
402 #endif
403     }
404     no_selection = false;
405 }
406
407
408 void InsetTabular::InsetKeyPress(XKeyEvent * xke)
409 {
410     if (the_locking_inset) {
411         the_locking_inset->InsetKeyPress(xke);
412         return;
413     }
414 }
415
416
417 UpdatableInset::RESULT InsetTabular::LocalDispatch(BufferView * bv, int action,
418                                                    string const & arg)
419 {
420     UpdatableInset::RESULT 
421         result;
422
423     no_selection = false;
424     if (((result=UpdatableInset::LocalDispatch(bv, action, arg)) == DISPATCHED)
425         || (result == DISPATCHED_NOUPDATE)) {
426
427         resetPos(bv->painter());
428         return result;
429     }
430     result=DISPATCHED;
431
432     if ((action < 0) && arg.empty())
433         return FINISHED;
434
435     if ((action != LFUN_DOWN) && (action != LFUN_UP) &&
436         (action != LFUN_DOWNSEL) && (action != LFUN_UPSEL))
437         cursor.x_fix = -1;
438     if (the_locking_inset) {
439         result=the_locking_inset->LocalDispatch(bv, action, arg);
440         if (result == DISPATCHED_NOUPDATE)
441             return result;
442         else if (result == DISPATCHED) {
443             bool upd = SetCellDimensions(bv->painter(), actcell, actrow);
444             the_locking_inset->ToggleInsetCursor(bv);
445             UpdateLocal(bv, upd);
446             the_locking_inset->ToggleInsetCursor(bv);
447             return result;
448         } else if (result == FINISHED) {
449             if ((action == LFUN_RIGHT) || (action == -1)) {
450                 cursor.pos = inset_pos + 1;
451                 resetPos(bv->painter());
452             }
453             the_locking_inset=0;
454             result = DISPATCHED;
455             return result;
456         }
457     }
458
459     HideInsetCursor(bv);
460     switch (action) {
461         // Normal chars not handled here
462     case -1:
463         break;
464         // --- Cursor Movements ---------------------------------------------
465     case LFUN_RIGHTSEL:
466         moveRight(bv, false);
467         sel_pos_end = cursor.pos;
468         UpdateLocal(bv, false);
469         break;
470     case LFUN_RIGHT:
471         result = moveRight(bv);
472         if (hasCharSelection()) {
473             sel_pos_start = sel_pos_end = cursor.pos;
474             UpdateLocal(bv, false);
475         } else
476             sel_pos_start = sel_pos_end = cursor.pos;
477           break;
478     case LFUN_LEFTSEL:
479         moveLeft(bv, false);
480         sel_pos_end = cursor.pos;
481         UpdateLocal(bv, false);
482         break;
483     case LFUN_LEFT:
484         result = moveLeft(bv);
485         if (hasCharSelection()) {
486             sel_pos_start = sel_pos_end = cursor.pos;
487             UpdateLocal(bv, false);
488         } else
489             sel_pos_start = sel_pos_end = cursor.pos;
490         break;
491     case LFUN_DOWNSEL:
492         moveDown();
493         sel_pos_end = cursor.pos;
494         UpdateLocal(bv, false);
495         break;
496     case LFUN_DOWN:
497         result= moveDown();
498         if (hasCharSelection()) {
499             sel_pos_start = sel_pos_end = cursor.pos;
500             UpdateLocal(bv, false);
501         } else
502             sel_pos_start = sel_pos_end = cursor.pos;
503         break;
504     case LFUN_UPSEL:
505         moveUp();
506         sel_pos_end = cursor.pos;
507         UpdateLocal(bv, false);
508         break;
509     case LFUN_UP:
510         result= moveUp();
511         if (hasCharSelection()) {
512             sel_pos_start = sel_pos_end = cursor.pos;
513             UpdateLocal(bv, false);
514         } else
515             sel_pos_start = sel_pos_end = cursor.pos;
516         break;
517     case LFUN_BACKSPACE:
518         break;
519     case LFUN_DELETE:
520         break;
521     case LFUN_HOME:
522         break;
523     case LFUN_END:
524         break;
525     case LFUN_TAB:
526         if (hasCharSelection()) {
527             sel_pos_start = sel_pos_end = cursor.pos;
528             UpdateLocal(bv, false);
529         }
530         sel_pos_start = sel_pos_end = cursor.pos;
531         moveNextCell();
532         break;
533     case LFUN_LAYOUT_TABLE:
534     {
535         int flag = (arg == "true");
536         MenuLayoutTable(flag);
537     }
538     break;
539     default:
540         result = UNDISPATCHED;
541         break;
542     }
543     if (result!=FINISHED) {
544         if (!the_locking_inset) {
545 #if 0       
546             if (oldcell != actcell)
547                 bview->getOwner()->getPopups().updateFormTabular();
548 #endif
549             ShowInsetCursor(bv);
550         }
551     } else
552         bv->unlockInset(this);
553     return result;
554 }
555
556
557 int InsetTabular::Latex(ostream & os, bool, bool) const
558 {
559     return tabular->Latex(os);
560 }
561
562
563 int InsetTabular::Ascii(ostream &) const
564 {
565     return 0;
566 }
567
568 int InsetTabular::Linuxdoc(ostream &) const
569 {
570     return 0;
571 }
572
573
574 int InsetTabular::DocBook(ostream &) const
575 {
576     return 0;
577 }
578
579
580 void InsetTabular::Validate(LaTeXFeatures & features) const
581 {
582     if (tabular->IsLongTabular())
583         features.longtable = true;
584 }
585
586
587 void InsetTabular::calculate_width_of_cells(Painter & pain,
588                                             LyXFont const & font) const
589 {
590     int cell = -1;
591     int maxAsc, maxDesc;
592     InsetText * inset;
593     
594     for(int i = 0; i < tabular->rows(); ++i) {
595         maxAsc = maxDesc = 0;
596         for(int j= 0; j < tabular->columns(); ++j) {
597             if (tabular->IsPartOfMultiColumn(i,j))
598                 continue;
599             ++cell;
600             inset = tabular->GetCellInset(cell);
601             maxAsc = max(maxAsc, inset->ascent(pain, font));
602             maxDesc = max(maxDesc, inset->descent(pain, font));
603             tabular->SetWidthOfCell(cell, inset->width(pain, font));
604         }
605         tabular->SetAscentOfRow(i, maxAsc + ADD_TO_HEIGHT);
606         tabular->SetDescentOfRow(i, maxDesc + ADD_TO_HEIGHT);
607     }
608 }
609
610
611 void InsetTabular::GetCursorPos(int & x, int & y) const
612 {
613     x = cursor.x-top_x;
614     y = cursor.y;
615 }
616
617
618 void InsetTabular::ToggleInsetCursor(BufferView * bv)
619 {
620     if (the_locking_inset) {
621         the_locking_inset->ToggleInsetCursor(bv);
622         return;
623     }
624
625     LyXFont font; // = the_locking_inset->GetFont(par, cursor.pos);
626
627     int asc = lyxfont::maxAscent(font);
628     int desc = lyxfont::maxDescent(font);
629   
630     if (cursor_visible)
631         bv->hideLockedInsetCursor();
632     else
633         bv->showLockedInsetCursor(cursor.x, cursor.y, asc, desc);
634     cursor_visible = !cursor_visible;
635 }
636
637
638 void InsetTabular::ShowInsetCursor(BufferView * bv)
639 {
640     if (!cursor_visible) {
641         LyXFont font; // = GetFont(par, cursor.pos);
642     
643         int asc = lyxfont::maxAscent(font);
644         int desc = lyxfont::maxDescent(font);
645         bv->fitLockedInsetCursor(cursor.x, cursor.y, asc, desc);
646         bv->showLockedInsetCursor(cursor.x, cursor.y, asc, desc);
647         cursor_visible = true;
648     }
649 }
650
651
652 void InsetTabular::HideInsetCursor(BufferView * bv)
653 {
654     if (cursor_visible)
655         ToggleInsetCursor(bv);
656 }
657
658
659 void InsetTabular::setPos(Painter & pain, int x, int y) const
660 {
661     cursor.y = cursor.pos = actcell = actrow = actcol = 0;
662     int ly = tabular->GetDescentOfRow(actrow);
663
664     // first search the right row
665     while((ly < y) && (actrow < tabular->rows())) {
666         cursor.y += tabular->GetDescentOfRow(actrow) +
667                 tabular->GetAscentOfRow(actrow+1) +
668             tabular->GetAdditionalHeight(tabular->GetCellNumber(actcol,actrow+1));
669         ++actrow;
670         ly = cursor.y + tabular->GetDescentOfRow(actrow);
671     }
672     actcell = tabular->GetCellNumber(actcol, actrow);
673
674     // now search the right column
675     int lx = tabular->GetWidthOfColumn(actcell) -
676         tabular->GetAdditionalWidth(actcell);
677     for(; !tabular->IsLastCellInRow(actcell) && (lx < x);
678         ++actcell,lx += tabular->GetWidthOfColumn(actcell) +
679             tabular->GetAdditionalWidth(actcell-1));
680     cursor.pos = ((actcell+1) * 2) - 1;
681     resetPos(pain);
682     if ((lx - (tabular->GetWidthOfColumn(actcell)/2)) < x) {
683         cursor.x = lx + top_x - 2;
684     } else {
685         --cursor.pos;
686         cursor.x = lx - tabular->GetWidthOfColumn(actcell) + top_x + 2;
687     }
688     resetPos(pain);
689 }
690
691
692 void InsetTabular::resetPos(Painter & pain) const
693 {
694     actrow = cursor.y = actcol = 0;
695
696     int cell = 0;
697     for(; (cell<actcell) && !tabular->IsLastRow(cell); ++cell) {
698         if (tabular->IsLastCellInRow(cell)) {
699             cursor.y += tabular->GetDescentOfRow(actrow) +
700                 tabular->GetAscentOfRow(actrow+1) +
701                 tabular->GetAdditionalHeight(cell+1);
702             ++actrow;
703         }
704     }
705     for(cell=actcell;!tabular->IsFirstCellInRow(cell);--cell)
706         ;
707     int lx = tabular->GetWidthOfColumn(actcell);
708     for(; (cell < actcell); ++cell) {
709         lx += tabular->GetWidthOfColumn(cell);
710         ++actcol;
711     }
712     cursor.x = lx - tabular->GetWidthOfColumn(actcell) + top_x + 2;
713     if (cursor.pos % 2) {
714         LyXFont font(LyXFont::ALL_SANE);
715         cursor.x += tabular->GetCellInset(actcell)->width(pain,font) +
716                 tabular->GetBeginningOfTextInCell(actcell);
717     }
718 }
719
720
721 bool InsetTabular::SetCellDimensions(Painter & pain, int cell, int row)
722 {
723     InsetText * inset = tabular->GetCellInset(cell);
724     LyXFont font(LyXFont::ALL_SANE);
725     int asc = inset->ascent(pain, font) + ADD_TO_HEIGHT;
726     int desc = inset->descent(pain, font) + ADD_TO_HEIGHT;
727     int maxAsc = tabular->GetAscentOfRow(row);
728     int maxDesc = tabular->GetDescentOfRow(row);
729     bool ret = tabular->SetWidthOfCell(cell, inset->width(pain, font));
730
731     if (maxAsc < asc) {
732         ret = true;
733         tabular->SetAscentOfRow(row, asc);
734     }
735     if (maxDesc < desc) {
736         ret = true;
737         tabular->SetDescentOfRow(row, desc);
738     }
739     return ret;
740 }
741
742
743 UpdatableInset::RESULT InsetTabular::moveRight(BufferView * bv, bool lock)
744 {
745     if (cursor.pos % 2) { // behind the inset
746         ++actcell;
747         if (actcell >= tabular->GetNumberOfCells())
748             return FINISHED;
749         ++cursor.pos;
750     } else if (lock) {
751         if (ActivateCellInset(bv))
752             return DISPATCHED;
753     } else {              // before the inset
754         ++cursor.pos;
755     }
756     resetPos(bv->painter());
757     return DISPATCHED_NOUPDATE;
758 }
759
760
761 UpdatableInset::RESULT InsetTabular::moveLeft(BufferView * bv, bool lock)
762 {
763     if (!cursor.pos)
764         return FINISHED;
765     --cursor.pos;
766     if (cursor.pos % 2) { // behind the inset
767         --actcell;
768     } else if (lock) {       // behind the inset
769         if (ActivateCellInset(bv, -1, -1))
770             return DISPATCHED;
771     }
772     resetPos(bv->painter());
773     return DISPATCHED_NOUPDATE;
774 }
775
776
777 UpdatableInset::RESULT InsetTabular::moveUp()
778 {
779     return DISPATCHED_NOUPDATE;
780 }
781
782
783 UpdatableInset::RESULT InsetTabular::moveDown()
784 {
785     return DISPATCHED_NOUPDATE;
786 }
787
788
789 bool InsetTabular::moveNextCell()
790 {
791     return false;
792 }
793
794
795 bool InsetTabular::movePrevCell()
796 {
797     return false;
798 }
799
800
801 bool InsetTabular::Delete()
802 {
803     return true;
804 }
805
806
807 void InsetTabular::SetFont(BufferView *, LyXFont const &, bool)
808 {
809 }
810
811
812 void InsetTabular::TabularFeatures(BufferView * bv, int feature, string val)
813 {
814     int
815         i,
816         sel_pos_start,
817         sel_pos_end,
818         setLines = 0,
819         setAlign = LYX_ALIGN_LEFT,
820         lineSet;
821     bool
822         what;
823
824     switch (feature) {
825       case LyXTabular::ALIGN_LEFT:
826           setAlign=LYX_ALIGN_LEFT;
827           break;
828       case LyXTabular::ALIGN_RIGHT:
829           setAlign=LYX_ALIGN_RIGHT;
830           break;
831       case LyXTabular::ALIGN_CENTER:
832           setAlign=LYX_ALIGN_CENTER;
833           break;
834       default:
835           break;
836     }
837     if (hasCellSelection()) {
838         if (sel_cell_start > sel_cell_end) {
839             sel_pos_start = sel_cell_end;
840             sel_pos_end = sel_cell_start;
841         } else {
842             sel_pos_start = sel_cell_start;
843             sel_pos_end = sel_cell_end;
844         }
845     } else
846         sel_pos_start = sel_pos_end = actcell;
847     switch (feature) {
848       case LyXTabular::SET_PWIDTH:
849           tabular->SetPWidth(actcell,val);
850           break;
851       case LyXTabular::SET_SPECIAL_COLUMN:
852       case LyXTabular::SET_SPECIAL_MULTI:
853           tabular->SetAlignSpecial(actcell,val,feature);
854           break;
855       case LyXTabular::APPEND_ROW:
856       {
857           // append the row into the tabular
858           tabular->AppendRow(actcell);
859           UpdateLocal(bv, true);
860           return;
861       }
862       case LyXTabular::APPEND_COLUMN:
863       { 
864           // append the column into the tabular
865           tabular->AppendColumn(actcell);
866           UpdateLocal(bv, true);
867           return;
868       }
869       case LyXTabular::DELETE_ROW:
870           RemoveTabularRow();
871           UpdateLocal(bv, true);
872           return;
873       case LyXTabular::DELETE_COLUMN:
874       {
875           /* delete the column from the tabular */ 
876           tabular->DeleteColumn(actcell);
877           UpdateLocal(bv, true);
878           return;
879       }
880       case LyXTabular::TOGGLE_LINE_TOP:
881           lineSet = !tabular->TopLine(actcell);
882           for(i=sel_pos_start; i<=sel_pos_end; ++i)
883               tabular->SetTopLine(i,lineSet);
884           UpdateLocal(bv, true);
885           return;
886     
887       case LyXTabular::TOGGLE_LINE_BOTTOM:
888           lineSet = !tabular->BottomLine(actcell); 
889           for(i=sel_pos_start; i<=sel_pos_end; ++i)
890               tabular->SetBottomLine(i,lineSet);
891           UpdateLocal(bv, true);
892           return;
893                 
894       case LyXTabular::TOGGLE_LINE_LEFT:
895           lineSet = !tabular->LeftLine(actcell);
896           for(i=sel_pos_start; i<=sel_pos_end; ++i)
897               tabular->SetLeftLine(i,lineSet);
898           UpdateLocal(bv, true);
899           return;
900
901       case LyXTabular::TOGGLE_LINE_RIGHT:
902           lineSet = !tabular->RightLine(actcell);
903           for(i=sel_pos_start; i<=sel_pos_end; ++i)
904               tabular->SetRightLine(i,lineSet);
905           UpdateLocal(bv, true);
906           return;
907       case LyXTabular::ALIGN_LEFT:
908       case LyXTabular::ALIGN_RIGHT:
909       case LyXTabular::ALIGN_CENTER:
910           for(i=sel_pos_start; i<=sel_pos_end; ++i)
911               tabular->SetAlignment(i,setAlign);
912           UpdateLocal(bv, true);
913           return;
914       case LyXTabular::MULTICOLUMN:
915       {
916           if (tabular->row_of_cell(sel_pos_start) !=
917               tabular->row_of_cell(sel_pos_end)) {
918               WriteAlert(_("Impossible Operation!"), 
919                          _("Multicolumns can only be horizontally."), 
920                          _("Sorry."));
921               return;
922           }
923           // just multicol for one Single Cell
924           if (!hasCellSelection()) {
925               // check wether we are completly in a multicol
926               if (tabular->IsMultiColumn(actcell)) {
927                   tabular->UnsetMultiColumn(actcell);
928                   UpdateLocal(bv, true);
929               } else {
930                   tabular->SetMultiColumn(actcell, 1);
931                   UpdateLocal(bv, false);
932               }
933               return;
934           }
935           // we have a selection so this means we just add all this
936           // cells to form a multicolumn cell
937           int
938               s_start, s_end;
939
940           if (sel_pos_start > sel_pos_end) {
941               s_start = sel_pos_end;
942               s_end = sel_pos_start;
943           } else {
944               s_start = sel_pos_start;
945               s_end = sel_pos_end;
946           }
947           tabular->SetMultiColumn(s_start, s_end);
948           cursor.pos = s_start;
949           sel_cell_end = sel_cell_start;
950           UpdateLocal(bv, true);
951           return;
952       }
953       case LyXTabular::SET_ALL_LINES:
954           setLines = 1;
955       case LyXTabular::UNSET_ALL_LINES:
956           for(i=sel_pos_start; i<=sel_pos_end; ++i)
957               tabular->SetAllLines(i, setLines);
958           UpdateLocal(bv, true);
959           return;
960       case LyXTabular::SET_LONGTABULAR:
961           tabular->SetLongTabular(true);
962           UpdateLocal(bv, true); // because this toggles displayed
963           return;
964       case LyXTabular::UNSET_LONGTABULAR:
965           tabular->SetLongTabular(false);
966           UpdateLocal(bv, true); // because this toggles displayed
967           return;
968       case LyXTabular::SET_ROTATE_TABULAR:
969           tabular->SetRotateTabular(true);
970           return;
971       case LyXTabular::UNSET_ROTATE_TABULAR:
972           tabular->SetRotateTabular(false);
973           return;
974       case LyXTabular::SET_ROTATE_CELL:
975           for(i=sel_pos_start; i<=sel_pos_end; ++i)
976               tabular->SetRotateCell(i,true);
977           return;
978       case LyXTabular::UNSET_ROTATE_CELL:
979           for(i=sel_pos_start; i<=sel_pos_end; ++i)
980               tabular->SetRotateCell(i,false);
981           return;
982       case LyXTabular::SET_LINEBREAKS:
983           what = !tabular->GetLinebreaks(actcell);
984           for(i=sel_pos_start; i<=sel_pos_end; ++i)
985               tabular->SetLinebreaks(i,what);
986           return;
987       case LyXTabular::SET_LTFIRSTHEAD:
988           tabular->SetLTHead(actcell,true);
989           return;
990       case LyXTabular::SET_LTHEAD:
991           tabular->SetLTHead(actcell,false);
992           return;
993       case LyXTabular::SET_LTFOOT:
994           tabular->SetLTFoot(actcell,false);
995           return;
996       case LyXTabular::SET_LTLASTFOOT:
997           tabular->SetLTFoot(actcell,true);
998           return;
999       case LyXTabular::SET_LTNEWPAGE:
1000           what = !tabular->GetLTNewPage(actcell);
1001           tabular->SetLTNewPage(actcell,what);
1002           return;
1003     }
1004 }
1005
1006 void InsetTabular::RemoveTabularRow()
1007 {
1008 }
1009
1010 bool InsetTabular::ActivateCellInset(BufferView * bv, int x, int y, int button)
1011 {
1012     // the cursor.pos has to be before the inset so if it isn't now just
1013     // reset the curor pos first!
1014     if (cursor.pos % 2) { // behind the inset
1015         --cursor.pos;
1016         resetPos(bv->painter());
1017     }
1018     UpdatableInset * inset =
1019         static_cast<UpdatableInset*>(tabular->GetCellInset(actcell));
1020     LyXFont font(LyXFont::ALL_SANE);
1021     if (x < 0)
1022         x = inset->width(bv->painter(), font) + top_x;
1023     if (y < 0)
1024         y = inset->descent(bv->painter(), font);
1025     inset_x = cursor.x - top_x + tabular->GetBeginningOfTextInCell(actcell);
1026     inset_y = cursor.y;
1027     inset->Edit(bv, x-inset_x, y-inset_y, button);
1028     if (!the_locking_inset)
1029         return false;
1030     UpdateLocal(bv, true);
1031     return true;
1032 }
1033
1034 bool InsetTabular::InsetHit(BufferView * bv, int x, int ) const
1035 {
1036     InsetText * inset = tabular->GetCellInset(actcell);
1037     int x1 = x + top_x;
1038
1039     if (cursor.pos % 2) { // behind the inset
1040         return (((x+top_x) < cursor.x) &&
1041                 ((x+top_x) > (cursor.x - inset->width(bv->painter(),
1042                                                       LyXFont(LyXFont::ALL_SANE)))));
1043     } else {
1044         int x2 = cursor.x + tabular->GetBeginningOfTextInCell(actcell);
1045         return ((x1 > x2) &&
1046                 (x1 < (x2 + inset->width(bv->painter(),
1047                                          LyXFont(LyXFont::ALL_SANE)))));
1048     }
1049 }