This patch against 1.1.4fix1 redoes the layout menu in the toolbar.
A) The menu is alphabetaized.
B) The menu now displays the depth too. For example, suppose you have an
enumerate of depth 1, with the enclosing environment a proof. The box in the
toolbar will show "Enumerate in Proof" (it was slightly widened for this) and
the menu will be twice as long, allowing you to chose either an "X in proof"
for all layouts X (which just sets the layout) or an "X" which sets both the
layout and the depth.
I am embedding lots of stuff in Proof and this change really helps to see
what's going on.
Issues/Problems
1) The action of setting layout+depth is two actions, undo-wise. This should
not be hard to fix.
2) LyXView::updateLayoutChoice is heavier. I tried to optimize it,
especially the do-nothing path, but it could still be slow, if DepthHook is
slow (e.g. a large document with no depth 0 paragraphs). An experiment showed
that other parts of LyX are much slower, so I guess this is not a big issue.
3) Some environments cannot be embedded. I think they should not appear in the
menu. How do I test this? Also, I guess that obsolete environments should not
appear at all (rather than being permanently disables, as they are now).
Please respong to my work email, [EMAIL PROTECTED]
diff -r -U 3 orig/lyx-1.1.4/src/BufferView.C lyx-1.1.4/src/BufferView.C
--- orig/lyx-1.1.4/src/BufferView.C Thu Feb 3 18:29:57 2000
+++ lyx-1.1.4/src/BufferView.C Thu Apr 6 00:59:13 2000
@@ -1008,6 +1008,12 @@
if (screen->FitCursor())
updateScrollbar();
screen->ShowCursor();
+
+ // G.K. - need to update layout menu (preformance seems
+ // reasonable. If this is slow, then this call can be moved to
+ // WorkAreaButtonRelease).
+
+ owner_->updateLayoutChoice();
}
return 0;
}
diff -r -U 3 orig/lyx-1.1.4/src/LyXView.C lyx-1.1.4/src/LyXView.C
--- orig/lyx-1.1.4/src/LyXView.C Mon Jan 17 22:04:30 2000
+++ lyx-1.1.4/src/LyXView.C Tue Apr 11 20:41:59 2000
@@ -33,13 +33,17 @@
#include "support/filetools.h" // OnlyFilename()
#include "layout.h"
#include "lyxtext.h"
+#include "lyx_cb.h"
extern FD_form_document * fd_form_document;
extern void AutoSave();
extern char updatetimer;
extern void QuitLyX();
+// All these belong in the LyXView class, I believe - G.K.
int current_layout = 0;
+int current_depth = 0; // G.K.
+LyXParagraph *last_p = NULL, *last_dp = NULL;
// This is very temporary
BufferView * current_view;
@@ -53,6 +57,10 @@
lyxerr[Debug::INIT] << "Initializing LyXFunc" << endl;
lyxfunc = new LyXFunc(this);
intl = new Intl;
+
+ // G.K.
+ cb_data.in_callback = false;
+ cb_data.owner = this;
}
@@ -275,12 +283,47 @@
last_textclass = -1;
}
+// Layout-and-depth in menu - G.K. 4/3/2000.
+// It is probably better to arrange the layout+depth combinations in a
+// hierarchal menu rather than in one long menu. However, this is beyond my
+// Xforms skills (and I don't like Xforms anyway).
+
+// Another possible improvement is somehow to arrange the menu so that the
+// previous depths are in the beginning, i.e. instead of
+// X in Enumerate, Y in Enumerate, ...
+// have
+// (in Enumerate) X, (in Enumerate) Y, ...
+// This would be more aesthetic, but I need a better wording than the above.
+
+void LyXView::lm_select(char layout)
+{
+ toolbar -> combox -> select(for_lm_select(layout));
+}
+
+struct to_order {
+ char layout;
+ char obs;
+ const char *key;
+};
+
+int compare_to(const void *f, const void *s)
+{
+ //printf("Comparing to %s\n", ((to_order *)f) -> key);
+ return strcmp(((to_order *)f)->key, ((to_order *)s)->key);
+}
void LyXView::updateLayoutChoice()
{
+#if 0
+ timeval tv1, tv2;
+
+ gettimeofday(&tv1, NULL);
+#endif
// Update the layout display
if (!toolbar->combox) return;
+ if ( cb_data.in_callback ) return;
+
// This has a side-effect that the layouts are not showed when no
// document is loaded.
if (bufferview == 0 || bufferview->buffer() == 0) {
@@ -289,28 +332,237 @@
return;
}
- // If textclass is different, we need to update the list
- if (toolbar->combox->empty() ||
- (last_textclass != int(buffer()->params.textclass))) {
+ LyXParagraph *start, *p;
+
+ // We always refer to the beginning of the selection, because this is
+ // what will be meaningful when we select from the menu.
+ if ( bufferview->text->selection )
+ start = bufferview->text->sel_start_cursor.par;
+ else
+ start = bufferview->text->cursor.par;
+
+ p = start;
+ int depth = p->GetDepth();
+
+ bool need_recalc = false;
+ do {
+ // If textclass is different, we need to update the list
+ if ( toolbar->combox->empty() ||
+ last_textclass != int(buffer()->params.textclass) ) {
+ need_recalc = true;
+ break;
+ }
+ if ( current_depth != depth ) {
+ need_recalc = true;
+ break;
+ }
+ if ( current_depth == 0 )
+ break; // need_recalc = false
+
+ /* This point is tricky, because it needs to be done fast (this
+ * function is called a lot) and also correctly.
+ * We do the following: we descend simultanuously from the current
+ * paragraph and from the last paragraph until we reach one of them
+ * (which is good, nothing needs to be done) or until we reach
+ * a different father (at which point we give up and recalculate
+ * the menu).
+ * The ideal solution is to make DepthHook a field of
+ * LyXParagraph.
+ * I don't test the footnote flag. Under the assumption that a
+ * footnote always starts with a paragraph of depth 0, this
+ * algorithm will catch this case without a special test.
+ */
+ if ( last_p == NULL ) {
+ need_recalc = true;
+ break;
+ }
+
+ LyXParagraph *frm_p = p,
+ *frm_last_p = last_p;
+
+ while ( frm_p && frm_last_p &&
+ frm_last_p != p && frm_p != last_p ) {
+ if ( frm_p -> GetDepth() < p -> GetDepth() ) {
+ need_recalc = frm_p != last_dp;
+ break;
+ }
+ if ( frm_last_p -> GetDepth() < last_p -> GetDepth() ) {
+ if ( last_dp != frm_last_p )
+ printf("Hmpf...\n");
+ // Continue with frm_p only
+ while ( frm_p && frm_p != last_p ) {
+ if ( frm_p -> GetDepth() < p -> GetDepth() ) {
+ need_recalc = frm_p != last_dp;
+ break;
+ }
+ frm_p = frm_p -> FirstPhysicalPar() -> Previous();
+ }
+ // The test of frm_p should be redundant, and in this
+ // case the current value of need_recalc is OK.
+ break;
+ }
+ frm_p = frm_p -> FirstPhysicalPar() -> Previous();
+ frm_last_p = frm_last_p -> FirstPhysicalPar() -> Previous();
+ }
+ } while(false);
+
+ last_p = p; // last_dp is updated below.
+
+#if 0
+ gettimeofday(&tv2, NULL);
+
+ printf("nr: %d (%d)\n", need_recalc, (tv2.tv_sec - tv1.tv_sec) * 1000000 +
+(tv2.tv_usec - tv1.tv_usec));
+#endif
+
+ if ( need_recalc ) {
toolbar->combox->clear();
- LyXTextClass const & tc =
textclasslist.TextClass(buffer()->params.textclass);
+
+ #define MAX_DEPTH 100
+
+ char buf[256], suffix[256];
+ to_order _to[256];
+ int counter, mdepth, i, j, cnl, cur_len, num_in_menu, tonum;
+
+ current_depth = depth;
+
+ // Calculate maximum length of class name
+ cnl = tonum = 0;
+ LyXTextClass const & tc = textclasslist.TextClass(
+ buffer()->params.textclass);
for (LyXTextClass::const_iterator cit = tc.begin();
- cit != tc.end(); ++cit) {
- if ((*cit).obsoleted_by().empty())
- toolbar->combox->addline((*cit).name().c_str());
+ cit != tc.end(); ++cit) {
+ _to[tonum].key = (*cit).name().c_str();
+ _to[tonum].obs = ! (*cit).obsoleted_by().empty();
+ _to[tonum].layout = tonum;
+ //printf("to[%d] = %d %d %s\n", tonum, _to[tonum].layout,
+_to[tonum].obs, _to[tonum].key);
+ tonum++;
+ int tmp = (*cit).name().length();
+ if ( tmp > cnl ) cnl = tmp;
+ }
+
+ qsort(_to, tonum, sizeof(_to[0]), &compare_to);
+ for ( i = 0; i < tonum; i++ ) {
+ //printf("to[%d] = %d %d %s\n", i, _to[i].layout, _to[i].obs,
+_to[i].key);
+ //printf ("fx[%d] = %d\n", _to[i].layout, i + 1);
+ cb_data.for_select[_to[i].layout] = i + 1;
+ }
+
+ // It seems that depth jumps (i.e. a paragraph of depth 3
+ // following a paragraph of depth 0) are legal, and are simply
+ // ignored when displaying/creating tex.
+
+ LayoutsCBdatum in_menu[MAX_DEPTH];
+ num_in_menu = 0;
+
+ LyXParagraph *next;
+ p = start;
+ for ( i = depth - 1; i >= 0 ; i-- ) {
+ // Note that DepthHook always descends, so I need the if.
+ if ( p -> GetDepth() > i )
+ next = p -> DepthHook(i);
+ // else next == p
+ if ( next != p ) {
+ in_menu[num_in_menu].layout = next -> GetLayout();
+ in_menu[num_in_menu++].depth = i;
+ } else
+ in_menu[num_in_menu - 1].depth = i;
+ p = next;
+
+ if ( i == depth - 1 )
+ last_dp = p;
+ }
+
+ // And invert it
+ for ( i = 0; i < num_in_menu / 2; i++ ) {
+ LayoutsCBdatum temp = in_menu[i];
+ in_menu[i] = in_menu[num_in_menu - 1 - i];
+ in_menu[num_in_menu - 1 - i] = temp;
+ }
+
+ // Useful later on
+ in_menu[num_in_menu].depth = depth;
+
+ // It seems selection numbers in Xforms start from 1.
+ counter = 1;
+
+ for ( mdepth = num_in_menu; mdepth >=0; mdepth-- ) {
+ suffix[0] = 0;
+
+ for ( i = mdepth - 1; i >= 0; i-- ) {
+ int tmp = strlen(suffix);
+
+ strcat(suffix, " in ");
+ strcat(suffix, textclasslist.Style(
+ buffer()->params.textclass, in_menu[i].layout)
+ .name().c_str());
+
+ //printf ("%d %d\n", strlen(suffix), cnl);
+ if ( strlen(suffix) + cnl > LAYOUTS_MAX_CHARS ) {
+ strcpy(suffix + tmp, " in...");
+ break;
+ }
+ }
+
+ cur_len = mdepth - i;
+
+ bool ok_to_show = true;
+ if ( mdepth >= cur_len ) {
+ // If we already have an X in Y in Z ... entry in the
+ // menu, even if for a different depth, we don't want
+ // to show an identical entry.
+ // Also if we have an X in Y in Z in W in the menu,
+ // we don't want to insert an X in Y in Z in ... for
+ // ... which is not W.
+ for ( i = mdepth + 1; i <= num_in_menu; i++ ) {
+ bool ident = true;
+ for ( j = 1; j < cur_len; j++ )
+ if ( in_menu[i - j].layout !=
+ in_menu[mdepth - j].layout ) {
+ ident = false;
+ break;
+ }
+ if ( ident ) {
+ ok_to_show = false;
+ break;
+ }
+ }
+
+ if ( ! ok_to_show )
+ continue; // the loop on mdepth.
+
+ }
+
+ int layout_num = 0;
+ for ( int i = 0; i < tonum; i++ ) {
+ // Maybe it's better to just drop the obsoleted
+ // layouts? The idea behind a disabled menu item is
+ // that it's a temporary situation.
+ if ( _to[i].obs )
+ sprintf(buf, "@N%s%s", _to[i].key, suffix);
else
- toolbar->combox->addline(("@N" +
(*cit).name()).c_str());
+ sprintf(buf, "%s%s", _to[i].key, suffix);
+ toolbar -> combox -> addline(buf);
+ cb_data.x[counter].layout = _to[i].layout;
+ cb_data.x[counter++].depth = in_menu[mdepth].depth;
+ if ( counter >= MAX_LAYOUTS )
+ goto end_mdepth;
+ }
}
+ end_mdepth:
last_textclass = int(buffer()->params.textclass);
- current_layout = 0;
+ current_layout = -1;
}
// we need to do this.
toolbar->combox->Redraw();
+ toolbar->combox->setcallback(LayoutsCB, &cb_data);
- char layout = bufferview->text->cursor.par->GetLayout();
+ char layout = start->GetLayout();
if (layout != current_layout){
- toolbar->combox->select(layout + 1);
+ // This works because if we change the depth, we get a large
+ // current_layout.
+ //toolbar->combox->select(cb_data.for_select[layout]);
+ lm_select(layout);
current_layout = layout;
}
}
diff -r -U 3 orig/lyx-1.1.4/src/LyXView.h lyx-1.1.4/src/LyXView.h
--- orig/lyx-1.1.4/src/LyXView.h Tue Dec 21 03:24:17 1999
+++ lyx-1.1.4/src/LyXView.h Sat Apr 15 18:40:17 2000
@@ -22,7 +22,7 @@
#include "menus.h"
#include "BufferView.h"
#include "layout.h"
-
+#include "lyx_cb.h" // G.K.
class LyXFunc;
class Toolbar;
class MiniBuffer;
@@ -145,5 +145,13 @@
This should probably be moved to the toolbar, but for now it's
here. (Asger) */
int last_textclass;
+
+ // G.K.
+ LayoutsCBdata cb_data;
+
+public:
+ int for_lm_select(char layout) { return cb_data.for_select[layout]; }
+ // Can't make it inline, it requires toolbar.h.
+ void lm_select(char layout);
};
#endif
diff -r -U 3 orig/lyx-1.1.4/src/lyx_cb.C lyx-1.1.4/src/lyx_cb.C
--- orig/lyx-1.1.4/src/lyx_cb.C Sat Apr 15 19:16:19 2000
+++ lyx-1.1.4/src/lyx_cb.C Sat Apr 15 18:47:33 2000
@@ -1288,11 +1288,45 @@
// candidate for move to LyXView
-void LayoutsCB(int sel, void *)
+// Layout-and-depth in menu - G.K. 4/3/2000.
+void LayoutsCB(int sel, void *_data)
{
- string tmp = tostr(sel);
+ if ( _data == NULL ) {
+ lyxerr << "ERROR (LayoutsCB) Layouts data NULL" << endl;
+ return;
+ }
+ // else
+
+ if ( sel == 0 )
+ return; // Illegal argument
+
+ // At some point We had to copy _data[sel] because the SetDepth
+ // might have changed the data array when recreating the menu.
+ // Probably this is not necessary anymore.
+ LayoutsCBdata *data = ((LayoutsCBdata *)_data);
+ LayoutsCBdatum datum = data->x[sel];
+
+ // This should be done cleaner. One obvious problem is that it
+ // is two actions, undo-wise.
+
+ // This disables recreating the menu during the SetDepth and
+ // Dispatch - otherwise it really looks weird.
+ data -> in_callback = true;
+
+ //printf("lyx_cb: %d %d %d\n", sel, datum.layout, datum.depth);
+ // Hmpf, what about data -> owner? Can it be used here instead?
+ if (current_view->available()) {
+ current_view->getScreen()->HideCursor();
+ current_view->update(-2);
+ current_view->text->SetDepth(datum.depth);
+ current_view->update(1);
+ }
+ string tmp = tostr((int)datum.layout);
current_view->owner()->getLyXFunc()->Dispatch(LFUN_LAYOUTNO,
tmp.c_str());
+
+ data -> in_callback = false;
+ data -> owner -> updateLayoutChoice();
}
diff -r -U 3 orig/lyx-1.1.4/src/lyx_cb.h lyx-1.1.4/src/lyx_cb.h
--- orig/lyx-1.1.4/src/lyx_cb.h Mon Jan 17 22:04:32 2000
+++ lyx-1.1.4/src/lyx_cb.h Sat Apr 15 18:49:18 2000
@@ -67,5 +67,26 @@
///
InsetUpdateStruct * next;
};
+
+// G.K.
+#define MAX_LAYOUTS 500
+
+extern void LayoutsCB(int, void *);
+
+struct LayoutsCBdata;
+class LyXView;
+
+struct LayoutsCBdatum {
+ char layout, depth;
+};
+
+struct LayoutsCBdata {
+ bool in_callback;
+ LyXView *owner;
+ LayoutsCBdatum x[MAX_LAYOUTS];
+
+ // This doesn't belong here proper... But it is combox information
+ char for_select[256];
+};
#endif
diff -r -U 3 orig/lyx-1.1.4/src/lyxfunc.C lyx-1.1.4/src/lyxfunc.C
--- orig/lyx-1.1.4/src/lyxfunc.C Sat Apr 15 19:15:52 2000
+++ lyx-1.1.4/src/lyxfunc.C Sat Apr 15 18:50:47 2000
@@ -1050,10 +1050,11 @@
lyxerr.debug() << "LFUN_LAYOUTNO: (sel) "<< sel << endl;
// Should this give a setMessage instead?
- if (sel == 0)
+ // Handled in lyx_cb now - G.K.
+ /*if (sel == 0)
return string(); // illegal argument
- --sel; // sel 1..., but layout 0...
+ --sel; // sel 1..., but layout 0...*/
// Pretend we got the name instead.
Dispatch(int(LFUN_LAYOUT),
@@ -1098,10 +1099,9 @@
owner->view()->update(-2);
owner->view()->text->
SetLayout(layout.second);
- owner->getToolbar()->combox->
- select(owner->view()->
- text->cursor.par->
- GetLayout() + 1);
+ // G.K.
+ owner -> lm_select(owner -> view() -> text ->
+ cursor.par -> GetLayout());
owner->view()->update(1);
}
}
diff -r -U 3 orig/lyx-1.1.4/src/lyxtext.h lyx-1.1.4/src/lyxtext.h
--- orig/lyx-1.1.4/src/lyxtext.h Mon Jan 17 22:04:35 2000
+++ lyx-1.1.4/src/lyxtext.h Sat Mar 4 00:32:58 2000
@@ -92,6 +92,10 @@
paragraphs */
void DecDepth();
+ /** Incomplete. do not use without reading the comments in the code
+ G.K. */
+ void SetDepth(char);
+
/** Get the depth at current cursor position
*/
int GetDepth() const { return cursor.par->GetDepth(); }
diff -r -U 3 orig/lyx-1.1.4/src/text2.C lyx-1.1.4/src/text2.C
--- orig/lyx-1.1.4/src/text2.C Thu Feb 3 20:43:42 2000
+++ lyx-1.1.4/src/text2.C Sat Apr 15 18:58:22 2000
@@ -57,7 +57,7 @@
current_font = GetFont(par, 0);
height = 0;
-
+
while (par) {
InsertParagraph(par, lastrow);
par = par->Next();
@@ -688,6 +688,68 @@
SetCursor(tmpcursor.par, tmpcursor.pos);
}
+/* Set depth over selection and
+ * make a total rebreak of those paragraphs
+ * This function does not perform all consistancy checks yet. G.K. */
+void LyXText::SetDepth(char d)
+{
+ // If there is no selection, just use the current paragraph
+ if (!selection) {
+ sel_start_cursor = cursor; /* dummy selection */
+ sel_end_cursor = cursor;
+ }
+
+ // We end at the next paragraph with depth 0
+ LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
+ LyXParagraph * undoendpar = endpar;
+
+ if (endpar && endpar->GetDepth()) {
+ while (endpar && endpar->GetDepth()) {
+ endpar = endpar->LastPhysicalPar()->Next();
+ undoendpar = endpar;
+ }
+ }
+ else if (endpar) {
+ endpar = endpar->Next(); /* because of parindentsetc. */
+ }
+
+ SetUndo(Undo::EDIT,
+ sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
+ undoendpar);
+
+ LyXCursor tmpcursor = cursor; /* store the current cursor */
+
+ /* ok we have a selection. This is always between sel_start_cursor
+ * and sel_end cursor */
+ cursor = sel_start_cursor;
+
+ bool anything_changed = false;
+
+ // NO CHECKS! This could create bibliography entries with non-zero
+ // depth, depth jumps (this is not a big problem) and other possible
+ // problems.
+ while (true) {
+ if (cursor.par->footnoteflag ==
+ sel_start_cursor.par->footnoteflag) {
+ cursor.par->FirstPhysicalPar()->depth = d;
+ }
+ if (cursor.par == sel_end_cursor.par)
+ break;
+ cursor.par = cursor.par->Next();
+ }
+
+ RedoParagraphs(sel_start_cursor, endpar);
+
+ /* we have to reset the selection, because the
+ * geometry could have changed */
+ SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
+ sel_cursor = cursor;
+ SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
+ UpdateCounters(cursor.row);
+ ClearSelection();
+ SetSelection();
+ SetCursor(tmpcursor.par, tmpcursor.pos);
+}
// set font over selection and make a total rebreak of those paragraphs
void LyXText::SetFont(LyXFont const & font, bool toggleall)
diff -r -U 3 orig/lyx-1.1.4/src/toolbar.C lyx-1.1.4/src/toolbar.C
--- orig/lyx-1.1.4/src/toolbar.C Tue Dec 21 03:24:23 1999
+++ lyx-1.1.4/src/toolbar.C Tue Mar 21 02:40:54 2000
@@ -308,12 +308,14 @@
xpos += standardspacing;
if (!combox)
combox = new Combox(FL_COMBOX_DROPLIST);
- combox->add(xpos, ypos, 135, height, 300);
+ // Widened combox to allow for Layout+depth
+ // combinations - G.K.
+ combox->add(xpos, ypos, LAYOUTS_LENGTH, height, 300);
combox->setcallback(LayoutsCB);
combox->resize(FL_RESIZE_ALL);
combox->gravity(NorthWestGravity, NorthWestGravity);
item = item->next;
- xpos += 135;
+ xpos += LAYOUTS_LENGTH;
break;
default:
xpos += standardspacing;
diff -r -U 3 orig/lyx-1.1.4/src/toolbar.h lyx-1.1.4/src/toolbar.h
--- orig/lyx-1.1.4/src/toolbar.h Tue Jan 25 00:17:07 2000
+++ lyx-1.1.4/src/toolbar.h Tue Mar 21 03:58:38 2000
@@ -22,6 +22,9 @@
#include "lyxlex.h"
#include "combox.h"
+#define LAYOUTS_LENGTH 200
+#define LAYOUTS_MAX_CHARS 30
+
/** The LyX toolbar class
This class {\em is} the LyX toolbar, and is not likely to be enhanced
further until we begin the move to Qt. We will probably have to make our