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