STR 3460.b: fixed scrollbar update in widget_browser

Also fixed a bug where a Manu item was accessed by index, which
already was out of sync.
This commit is contained in:
Matthias Melcher 2021-12-08 20:52:33 +01:00
parent c1edba3137
commit 1be158a840
6 changed files with 153 additions and 81 deletions

View File

@ -147,6 +147,7 @@ static void delete_children(Fl_Type *p) {
for (f = p; f && f->next && f->next->level > p->level; f = f->next) {/*empty*/}
for (; f != p; ) {
Fl_Type *g = f->prev;
widget_browser->deleting(f);
delete f;
f = g;
}
@ -158,6 +159,7 @@ void delete_all(int selected_only) {
if (f->selected || !selected_only) {
delete_children(f);
Fl_Type *g = f->next;
widget_browser->deleting(f);
delete f;
f = g;
} else f = f->next;
@ -250,13 +252,24 @@ const char* Fl_Type::title() {
return type_name();
}
// add a list of widgets as a new child of p:
/**
Add this list/tree of widgets as a new child of p.
\c this is not part of the widget browser. \c p should be in the
widget_browser, so \c Fl_Type::first and \c Fl_Type::last are valid for \c p.
This methods updates the widget_browser.
\param[in] p insert \c this tree as a child of \c p
*/
void Fl_Type::add(Fl_Type *p) {
if (p && parent == p) return;
undo_checkpoint();
parent = p;
// p is not in the Widget_Browser, so we must run the linked list to find the last entry
Fl_Type *end = this;
while (end->next) end = end->next;
// run the list again to set the future node levels
Fl_Type *q;
int newlevel;
if (p) {
@ -268,6 +281,7 @@ void Fl_Type::add(Fl_Type *p) {
}
for (Fl_Type *t = this->next; t; t = t->next) t->level += (newlevel-level);
level = newlevel;
// now link this tree after p
if (q) {
prev = q->prev;
prev->next = this;
@ -283,28 +297,52 @@ void Fl_Type::add(Fl_Type *p) {
last = end;
prev = end->next = 0;
}
// tell this that it was added, so it can update itself
if (p) p->add_child(this,0);
open_ = 1;
fixvisible(this);
set_modflag(1);
// run the p tree a last time to make sure the widget_browser updates correctly
Fl_Type *a = p;
for (Fl_Type *t = this; t && a != end; a = t, t = t->next)
widget_browser->inserting(a, t);
widget_browser->redraw();
}
// add to a parent before another widget:
/**
Add this list/tree of widgets as a new sibling before p.
\c this is not part of the widget browser. \c p should be in the
widget_browser, so \c Fl_Type::first and \c Fl_Type::last are valid for \c p.
This methods updates the widget_browser.
\param[in] p insert \c this tree as a child of \c p
*/
void Fl_Type::insert(Fl_Type *g) {
// p is not in the Widget_Browser, so we must run the linked list to find the last entry
Fl_Type *end = this;
while (end->next) end = end->next;
// this wil get the sam parent as g
parent = g->parent;
// run the list again to set the future node levels
int newlevel = g->level;
visible = g->visible;
for (Fl_Type *t = this->next; t; t = t->next) t->level += newlevel-level;
level = newlevel;
// insert this in the list before g
prev = g->prev;
if (prev) prev->next = this; else first = this;
end->next = g;
g->prev = end;
fixvisible(this);
// tell parent that it has a new child, so it can update itself
if (parent) parent->add_child(this, g);
// run this tree a last time to make sure the widget_browser updates correctly
Fl_Type *a = prev;
for (Fl_Type *t = this; t && a != end; a = t, t = t->next)
if (a)
widget_browser->inserting(a, t);
widget_browser->redraw();
}
@ -326,27 +364,39 @@ int Fl_Type::msgnum() {
/**
Remove this node and all its children from the parent node.
This does not delete anything. The resulting list//tree will no longer be in
the widget_browser, so \c Fl_Type::first and \c Fl_Type::last do not apply
to it.
\return the node that follows this node after the operation; can be NULL
*/
Fl_Type *Fl_Type::remove() {
// -- find the last child of this node
// find the last child of this node
Fl_Type *end = this;
for (;;) {
if (!end->next || end->next->level <= level) break;
if (!end->next || end->next->level <= level)
break;
end = end->next;
}
// -- unlink this node from the previous one
if (prev) prev->next = end->next;
else first = end->next;
// -- unlink the last child from their next node
if (end->next) end->next->prev = prev;
else last = prev;
// unlink this node from the previous one
if (prev)
prev->next = end->next;
else
first = end->next;
// unlink the last child from their next node
if (end->next)
end->next->prev = prev;
else
last = prev;
Fl_Type *r = end->next;
prev = end->next = 0;
// -- allow the parent to update changes in the UI
// allow the parent to update changes in the UI
if (parent) parent->remove_child(this);
parent = 0;
widget_browser->redraw_lines();
// tell the widget_browser that we removed some nodes
for (Fl_Type *t = this; t; t = t->next)
widget_browser->deleting(t);
widget_browser->redraw();
selection_changed(0);
return r;
@ -388,14 +438,23 @@ void Fl_Type::open() {
printf("Open of '%s' is not yet implemented\n",type_name());
}
// move f (and its children) into list before g:
// returns pointer to whatever is after f & children
/**
Move this node (and its children) into list before g.
\param[in] p move \c this tree before \c p
*/
void Fl_Type::move_before(Fl_Type* g) {
if (level != g->level) printf("move_before levels don't match! %d %d\n",
level, g->level);
// Find the last child in the list
Fl_Type* n;
for (n = next; n && n->level > level; n = n->next) {/*empty*/}
for (n = next; n && n->level > level; n = n->next) ;
if (n == g) return;
// Tell the widget browser that we delete them
for (n = next; n && n->level > level; n = n->next)
widget_browser->deleting(n);
// now link this tree before g
Fl_Type *l = n ? n->prev : Fl_Type::last;
prev->next = n;
if (n) n->prev = prev; else Fl_Type::last = prev;
@ -403,8 +462,13 @@ void Fl_Type::move_before(Fl_Type* g) {
l->next = g;
if (prev) prev->next = this; else Fl_Type::first = this;
g->prev = l;
// tell parent that it has a new child, so it can update itself
if (parent && is_widget()) parent->move_child(this,g);
widget_browser->inserting(g, this);
// run this tree a last time to make sure the widget_browser updates correctly
Fl_Type *a = prev;
for (Fl_Type *t = this; t && a != n; a = t, t = t->next)
if (a)
widget_browser->inserting(a, t);
widget_browser->display(this);
widget_browser->redraw();
}

View File

@ -1089,7 +1089,7 @@ extern Fl_Menu_Item Main_Menu[];
// Calculate new bounding box of selected widgets:
void Fl_Window_Type::fix_overlay() {
Main_Menu[40].label("Hide O&verlays");
overlay_item->label("Hide O&verlays");
overlays_invisible = 0;
recalc = 1;
((Overlay_Window *)(this->o))->redraw_overlay();
@ -1120,8 +1120,10 @@ void redraw_overlays() {
void toggle_overlays(Fl_Widget *,void *) {
overlays_invisible = !overlays_invisible;
if (overlays_invisible) Main_Menu[40].label("Show O&verlays");
else Main_Menu[40].label("Hide O&verlays");
if (overlays_invisible)
overlay_item->label("Show O&verlays");
else
overlay_item->label("Hide O&verlays");
for (Fl_Type *o=Fl_Type::first; o; o=o->next)
if (o->is_window()) {

View File

@ -127,6 +127,9 @@ Fl_Menu_Item *widgetbin_item = NULL;
/// Menuitem to show or hide the source view, label will change if view is visible.
Fl_Menu_Item *sourceview_item = NULL;
/// Menuitem to show or hide the editing overlay, label will change if overlay visibility changes.
Fl_Menu_Item *overlay_item = NULL;
////////////////////////////////////////////////////////////////
/// Filename of the current .fl design file
@ -1426,6 +1429,7 @@ void make_main_window() {
history_item = (Fl_Menu_Item*)main_menubar->find_item(open_history_cb);
widgetbin_item = (Fl_Menu_Item*)main_menubar->find_item(toggle_widgetbin_cb);
sourceview_item = (Fl_Menu_Item*)main_menubar->find_item((Fl_Callback*)toggle_sourceview_cb);
overlay_item = (Fl_Menu_Item*)main_menubar->find_item((Fl_Callback*)toggle_overlays);
main_menubar->global();
fill_in_New_Menu();
main_window->end();

View File

@ -63,6 +63,7 @@ extern Fl_Menu_Item *save_item;
extern Fl_Menu_Item *history_item;
extern Fl_Menu_Item *widgetbin_item;
extern Fl_Menu_Item *sourceview_item;
extern Fl_Menu_Item *overlay_item;
extern int modflag;

View File

@ -47,26 +47,26 @@ Widget_Browser *widget_browser = NULL;
Shortcut to have the widget browser graphics refreshed soon.
*/
void redraw_browser() {
widget_browser->redraw();
widget_browser->redraw();
}
/**
Shortcut to create the widget browser.
*/
Fl_Widget *make_widget_browser(int x,int y,int w,int h) {
return (widget_browser = new Widget_Browser(x,y,w,h));
return (widget_browser = new Widget_Browser(x,y,w,h));
}
/**
Make sure thet the caller is visible in the widget browser.
\param[in] caller scroll the browser in y so that caller
is visible (may be NULL)
is visible (may be NULL)
*/
void redraw_widget_browser(Fl_Type *caller)
{
if (caller)
widget_browser->display(caller);
widget_browser->redraw();
if (caller)
widget_browser->display(caller);
widget_browser->redraw();
}
/**
@ -75,7 +75,7 @@ void redraw_widget_browser(Fl_Type *caller)
\oaram[in] v the new selection state (1=select, 0=de-select)
*/
void select(Fl_Type *o, int v) {
widget_browser->select(o,v,1);
widget_browser->select(o,v,1);
}
/**
@ -83,14 +83,14 @@ void select(Fl_Type *o, int v) {
\param[in] o select this node
*/
void select_only(Fl_Type *o) {
widget_browser->select_only(o,1);
widget_browser->select_only(o,1);
}
/**
Deselect all nodes in the widget browser.
*/
void deselect() {
widget_browser->deselect();
widget_browser->deselect();
}
/**
@ -119,20 +119,20 @@ void reveal_in_browser(Fl_Type *t) {
// ---- local functions
/**
Copy the given string str to buffer p with no more than maxl characters.
Copy the given string str to buffer p with no more than maxl characters.
Add "..." if string was truncated.
Add "..." if string was truncated.
Quote characters are NOT counted.
Quote characters are NOT counted.
\param[out] p return the resulting string in this buffer, terminated with
\param[out] p return the resulting string in this buffer, terminated with
a NUL byte
\param[in] str copy this string; utf8 aware
\param[in] maxl maximum number of letter to copy until we print
\param[in] str copy this string; utf8 aware
\param[in] maxl maximum number of letter to copy until we print
the elipsis (...)
\param[in] auote if set, the resulting string is embedded in double quotes
\returns pointer to end of string (before terminating null byte).
\note the buffer p must be large enough to hold (4 * (maxl+1) + 1) bytes
\param[in] auote if set, the resulting string is embedded in double quotes
\returns pointer to end of string (before terminating null byte).
\note the buffer p must be large enough to hold (4 * (maxl+1) + 1) bytes
or (4 * (maxl+1) + 3) bytes if quoted, e.g. "123..." because each UTF-8
character can consist of 4 bytes, "..." adds 3 bytes, quotes '""' add two
bytes, and the terminating null byte adds another byte.
@ -177,7 +177,7 @@ static char *copy_trunc(char *p, const char *str, int maxl, int quote)
*/
Widget_Browser::Widget_Browser(int X,int Y,int W,int H,const char*l)
: Fl_Browser_(X,Y,W,H,l),
pushedtitle(NULL)
pushedtitle(NULL)
{
type(FL_MULTI_BROWSER);
Fl_Widget::callback(callback_stub);
@ -254,26 +254,26 @@ int Widget_Browser::incr_height() const {
}
/**
Draw an item in the widget browser.
Draw an item in the widget browser.
A browser line starts with a variable size space. This space directly
relates to the level of the type entry.
A browser line starts with a variable size space. This space directly
relates to the level of the type entry.
If this type has the ability to store children, a triangle follows,
pointing right (closed) or pointing down (open, children shown).
If this type has the ability to store children, a triangle follows,
pointing right (closed) or pointing down (open, children shown).
Next follows an icon that is specific to the type. This makes it easy to
spot certain types.
Next follows an icon that is specific to the type. This makes it easy to
spot certain types.
Now follows some text. For classes and widgets, this is the type itself,
followed by the name of the object. Other objects show their content as
text, possibly abbreviated with an ellipsis.
Now follows some text. For classes and widgets, this is the type itself,
followed by the name of the object. Other objects show their content as
text, possibly abbreviated with an ellipsis.
\param v v is a pointer to the actual widget type and can be cast safely
to Fl_Type
\param X,Y these give the position in window coordinates of the top left
corner of this line
*/
\param v v is a pointer to the actual widget type and can be cast safely
to Fl_Type
\param X,Y these give the position in window coordinates of the top left
corner of this line
*/
void Widget_Browser::item_draw(void *v, int X, int Y, int, int) const {
// cast to a more general type
Fl_Type *l = (Fl_Type *)v;
@ -427,19 +427,19 @@ void Widget_Browser::callback() {
}
/**
Override the event handling for this browser.
Override the event handling for this browser.
The vertical mouse position corresponds to an entry in the type tree.
The horizontal position has the following hot zones:
- 0-3 is the widget frame and ignored
- the next hot zone starts 12*indent pixels further to the right
- the next 13 pixels refer to the arrow that indicates children for the item
- 18 pixels follow for the icon
- the remaining part is filled with text
The vertical mouse position corresponds to an entry in the type tree.
The horizontal position has the following hot zones:
- 0-3 is the widget frame and ignored
- the next hot zone starts 12*indent pixels further to the right
- the next 13 pixels refer to the arrow that indicates children for the item
- 18 pixels follow for the icon
- the remaining part is filled with text
\param[in] e the incoming event type
\return 0 if the event is not supported, and 1 if the event was "used up"
*/
\param[in] e the incoming event type
\return 0 if the event is not supported, and 1 if the event was "used up"
*/
int Widget_Browser::handle(int e) {
static Fl_Type *title;
Fl_Type *l;

View File

@ -34,29 +34,30 @@ extern void reveal_in_browser(Fl_Type *t);
class Widget_Browser : public Fl_Browser_
{
friend class Fl_Type;
friend class Fl_Type;
static void callback_stub(Fl_Widget *o, void *) {
((Widget_Browser *)o)->callback();
}
static void callback_stub(Fl_Widget *o, void *) {
((Widget_Browser *)o)->callback();
}
Fl_Type* pushedtitle;
Fl_Type* pushedtitle;
// required routines for Fl_Browser_ subclass:
void *item_first() const ;
void *item_next(void *) const ;
void *item_prev(void *) const ;
int item_selected(void *) const ;
void item_select(void *,int);
int item_width(void *) const ;
int item_height(void *) const ;
void item_draw(void *,int,int,int,int) const ;
int incr_height() const ;
// required routines for Fl_Browser_ subclass:
void *item_first() const ;
void *item_next(void *) const ;
void *item_prev(void *) const ;
int item_selected(void *) const ;
void item_select(void *,int);
int item_width(void *) const ;
int item_height(void *) const ;
void item_draw(void *,int,int,int,int) const ;
int incr_height() const ;
public:
int handle(int);
void callback();
Widget_Browser(int,int,int,int,const char * =0);
Widget_Browser(int,int,int,int,const char * =NULL);
int handle(int);
void callback();
void deleting(Fl_Type *inType) { Fl_Browser_::deleting((void*)inType); }
};
#endif // _FLUID_WIDGET_BROWSER_H