Author: matt
Date: 2012-07-28 06:38:18 -0700 (Sat, 28 Jul 2012)
New Revision: 9648
Log:
Fluid3: edit labels and widget names right in the tree view. Very comfortable.
Modified:
branches/branch-3.0/documentation/src/fluid3.dox
branches/branch-3.0/fluid/Fl_Type.cxx
branches/branch-3.0/fluid/Fl_Type.h
branches/branch-3.0/fluid1/Fl_Widget_Type.cxx
branches/branch-3.0/include/fltk3/MenuWindow.h
branches/branch-3.0/include/fltk3/Rectangle.h
branches/branch-3.0/src/fltk3/MenuWindow.cxx
branches/branch-3.0/src/fltk3/Widget.cxx
Modified: branches/branch-3.0/documentation/src/fluid3.dox
===================================================================
--- branches/branch-3.0/documentation/src/fluid3.dox 2012-07-27 22:12:52 UTC
(rev 9647)
+++ branches/branch-3.0/documentation/src/fluid3.dox 2012-07-28 13:38:18 UTC
(rev 9648)
@@ -690,6 +690,10 @@
"Earlier" and "Later". This does not affect
the positions of windows or functions.
+When editing a projects, the selected items will be sorted in
+case-sensitive alphabetic order. Holding the Alt key when selecting
+<i>Sort</i> will sort in case-insensitive order.
+
\par Edit/Earlier (F2)
\par
@@ -710,8 +714,11 @@
\par
Creates a new Fl_Group and make all the currently
-selected widgets children of it.
+selected widgets children of it. Holding the Alt key when selecting
+this menu item will create a group that is one grid space bigger
+than the bounding box of all selected widgets.
+
\par Edit/Ungroup (F8)
\par
Modified: branches/branch-3.0/fluid/Fl_Type.cxx
===================================================================
--- branches/branch-3.0/fluid/Fl_Type.cxx 2012-07-27 22:12:52 UTC (rev
9647)
+++ branches/branch-3.0/fluid/Fl_Type.cxx 2012-07-28 13:38:18 UTC (rev
9648)
@@ -40,6 +40,7 @@
#include <fltk3/run.h>
#include <fltk3/ask.h>
#include <fltk3/Browser_.h>
+#include <fltk3/MenuWindow.h>
#include <fltk3/draw.h>
#include <fltk3/filename.h>
#include <stdlib.h>
@@ -209,6 +210,10 @@
class Widget_Browser : public fltk3::Browser_ {
friend class Fl_Type;
+ static void handle_second_single_click_i(void*);
+
+ Fl_Type* last_clicked;
+
// required routines for fltk3::Browser_ subclass:
void *item_first() const ;
void *item_next(void *) const ;
@@ -222,6 +227,7 @@
public:
+ void handle_second_single_click();
int handle(int);
void callback();
Widget_Browser(int,int,int,int,const char * =0);
@@ -257,7 +263,7 @@
: fltk3::Browser_(X,Y,W,H,l) {
type(fltk3::MULTI_BROWSER);
Widget::callback(Widget_Browser_callback);
- when(fltk3::WHEN_RELEASE);
+ when(fltk3::WHEN_RELEASE|fltk3::WHEN_NOT_CHANGED);
}
void *Widget_Browser::item_first() const {return Fl_Type::first;}
@@ -415,6 +421,7 @@
W += int(fltk3::width(buf));
}
} else {
+ // FIXME: utf8!
const char* c = l->title();
char buf[60]; char* p = buf;
for (int i = 55; i--;) {
@@ -434,14 +441,132 @@
widget_browser->redraw();
}
+
+extern Fl_Panel* the_panel;
+
+/*
+ This method allow editing simple text inline.
+
+ When clicking an already selected editable item, this method will pop up a
+ small window that allow for quick editing of the item value or label.
+
+ Making sure that a second click is not confused with a double click takes
+ some effort in the callback code, causing a timeout, which in turn is canceled
+ by a double click.
+ */
+void Widget_Browser::handle_second_single_click()
+{
+ if (!last_clicked)
+ return;
+ // find the text that we will edit first
+ const char* text = 0L;
+ if (last_clicked->name()) {
+ text = last_clicked->name();
+ } else if (last_clicked->label()) {
+ text = last_clicked->label();
+ } else {
+ return;
+ }
+ // count the lines in the text
+ int nlines = 1;
+ const char *s = text;
+ while (*s) { if (*s=='\n') nlines++; s++; }
+ if (nlines>10) nlines = 10;
+ // find the y position of the clicked item (the mouse event is no longer
reliable)
+ int yp = -position();
+ Fl_Type *t = (Fl_Type*)item_first();
+ while (t && t!=last_clicked) {
+ yp += item_height(t);
+ t = (Fl_Type*)item_next(t);
+ }
+ if (!t)
+ return;
+ // if the item has a comment, skip that
+ if (t->comment())
+ yp += textsize()-1;
+ // find the x position and width of the name
+ fltk3::font(textfont(), textsize());
+ int xp = x() + fltk3::box_dx(box()) + 3 + 18 + 8 + t->level * 12;
+ if (t->is_widget() || t->is_class()) {
+ const char* c = subclassname(t);
+ if (!strncmp(c,"fltk3::",7)) c += 7;
+ xp += int(fltk3::width(c)+fltk3::width('n'));
+ }
+ // use the widget width minus the x position, but use some minimum width
+ int wp = w()-xp-fltk3::box_dx(box());
+ if (scrollbar.visible()) wp-=scrollbar_width();
+ if (nlines>1) {
+ if (wp<320) wp = 320;
+ } else {
+ if (wp<200) wp = 200;
+ }
+ int hp = nlines*fltk3::height()+fltk3::DOWN_BOX->dh(); // FIXME: wrap and
resize if needed
+ // adjust coordinates to global and use a menu window
+ xp += dx_window() + window()->x();
+ yp += dy_window() + window()->y();
+ // open a modal dialog with an input widget
+ fltk3::PopupWindow* w = new fltk3::PopupWindow(xp, yp, wp, hp);
+ fltk3::Input *input = new fltk3::Input(0, 0, wp, hp);
+ if (nlines) input->type(fltk3::MULTILINE_INPUT);
+ input->box(fltk3::DOWN_BOX);
+ input->textfont(textfont());
+ input->textsize(textsize());
+ input->value(text);
+ input->position(0, strlen(input->value()));
+ input->callback(w->hide_i, w);
+ input->when(fltk3::WHEN_ENTER_KEY_ALWAYS);
+ if (w->popup()==input) {
+ int mod = 0;
+ if (strcmp(input->value(), text)) {
+ // FIXME: there are certain illegal characters that must be avoided!
+ if (t->name()) {
+ t->name(input->value());
+ } else if (t->label()) {
+ t->label(input->value());
+ }
+ mod = 1;
+ }
+ redraw_browser();
+ if (mod) {
+ if (the_panel)
+ Fl_Panel::propagate_load(the_panel);
+ set_modflag(1);
+ }
+ }
+ delete w;
+}
+
+
+void Widget_Browser::handle_second_single_click_i(void* d)
+{
+ ((Widget_Browser*)d)->handle_second_single_click();
+}
+
+
void Widget_Browser::callback() {
- selection_changed((Fl_Type*)selection());
+ if (changed()) {
+ // update evrything around the new selection
+ selection_changed((Fl_Type*)selection());
+ } else {
+ // on a single click, we may be able to edit some value directly
+ if ( fltk3::event()==fltk3::RELEASE ) {
+ last_clicked = (Fl_Type*)find_item(fltk3::event_y());
+ if (last_clicked && last_clicked->selected) {
+ // add a timeout to make sure that we have a single click, not a
double click
+ fltk3::add_timeout(0.5, handle_second_single_click_i, this);
+ }
+ }
+ }
}
+
int Widget_Browser::handle(int e) {
static Fl_Type *title;
Fl_Type *l;
int X,Y,W,H; bbox(X,Y,W,H);
+ if (e!=fltk3::MOVE) {
+ fltk3::remove_timeout(handle_second_single_click_i, this);
+ }
switch (e) {
case fltk3::PUSH:
if (!fltk3::event_inside(X,Y,W,H)) break;
@@ -472,8 +597,9 @@
case fltk3::RELEASE:
if (!title) {
l = (Fl_Type*)find_item(fltk3::event_y());
- if (l && l->new_selected && (fltk3::event_clicks() ||
fltk3::event_state(fltk3::CTRL)))
- l->open();
+ if (l && l->new_selected && (fltk3::event_clicks() ||
fltk3::event_state(fltk3::CTRL))) {
+ l->open();
+ }
break;
}
l = pushedtitle;
@@ -1869,8 +1995,32 @@
hide();
}
+extern fltk3::Window* widgetbin_panel;
+/**
+ Override show() to make sure that widgets don;t overlap.
+ Specifically, the widget bin and widget panel tend open in the same position.
+ One panel needs to be moved which interrupts workflow. This function moves
+ the WIdget Panel away from the Widget Bin.
+ */
+void Fl_Panel::show()
+{
+ if (shown()) {
+ // just raise th window, nothing else
+ fltk3::DoubleWindow::show();
+ } else {
+ // show the window, then avoid overlap
+ fltk3::DoubleWindow::show();
+ if (widgetbin_panel && widgetbin_panel->shown()) {
+ if (this->intersects(*widgetbin_panel)) {
+ position(x(), widgetbin_panel->b()+40);
+ }
+ }
+ }
+}
+
+
//
// End of "$Id$".
//
Modified: branches/branch-3.0/fluid/Fl_Type.h
===================================================================
--- branches/branch-3.0/fluid/Fl_Type.h 2012-07-27 22:12:52 UTC (rev 9647)
+++ branches/branch-3.0/fluid/Fl_Type.h 2012-07-28 13:38:18 UTC (rev 9648)
@@ -1211,6 +1211,7 @@
Fl_Panel(int x, int y, int w, int h, const char *name=0L);
~Fl_Panel();
void load(RTTI_Query query);
+ void show(); // override the widget show()
static void *const LOAD;
static int numselected;
Modified: branches/branch-3.0/fluid1/Fl_Widget_Type.cxx
===================================================================
--- branches/branch-3.0/fluid1/Fl_Widget_Type.cxx 2012-07-27 22:12:52 UTC
(rev 9647)
+++ branches/branch-3.0/fluid1/Fl_Widget_Type.cxx 2012-07-28 13:38:18 UTC
(rev 9648)
@@ -1874,7 +1874,16 @@
void Fl_Widget_Type::open() {
if (!the_panel) the_panel = make_widget_panel();
load_panel();
- if (numselected) the_panel->show();
+ if (numselected) {
+ if (the_panel->visible_r()) {
+ // just pop it to the front
+ the_panel->show();
+ } else {
+ // show the panel and make sure it is not under the widget bin
+ the_panel->show();
+ if (the_panel->con
+ }
+ }
}
Fl_Type *Fl_Type::current;
Modified: branches/branch-3.0/include/fltk3/MenuWindow.h
===================================================================
--- branches/branch-3.0/include/fltk3/MenuWindow.h 2012-07-27 22:12:52 UTC
(rev 9647)
+++ branches/branch-3.0/include/fltk3/MenuWindow.h 2012-07-28 13:38:18 UTC
(rev 9648)
@@ -73,8 +73,24 @@
};
+
+
+ class PopupWindow : public fltk3::MenuWindow {
+ bool pUserPosition;
+ fltk3::Widget* pTrigger;
+ public:
+ static void hide_i(fltk3::Widget*, void*);
+ int handle(int);
+ PopupWindow(int X, int Y, int W, int H, const char *label = 0);
+ PopupWindow(int W, int H, const char *label = 0);
+ ~PopupWindow();
+ Widget* popup();
+ };
+
+
}
+
#endif
//
Modified: branches/branch-3.0/include/fltk3/Rectangle.h
===================================================================
--- branches/branch-3.0/include/fltk3/Rectangle.h 2012-07-27 22:12:52 UTC
(rev 9647)
+++ branches/branch-3.0/include/fltk3/Rectangle.h 2012-07-28 13:38:18 UTC
(rev 9648)
@@ -42,86 +42,89 @@
class FLTK3_EXPORT Rectangle : public Object {
protected:
- int x_, y_, w_, h_;
-
- public:
-
- /*! Left edge */
- int x() const {return x_;}
- /*! Top edge */
- int y() const {return y_;}
- /*! Distance between left and right edges */
- int w() const {return w_;}
- /*! Distance between top and bottom edges */
- int h() const {return h_;}
- /*! Return x()+w(), the right edge of the rectangle. */
- int r() const {return x_+w_;}
- /*! Return y()+h(), the bottom edge of the rectangle. */
- int b() const {return y_+h_;}
- /*! Move the rectangle so the left edge is at \a v. */
- void x(int v) {x_ = v;}
- /*! Move the rectangle so the top edge is at \a v. */
- void y(int v) {y_ = v;}
- /*! Change w() by moving the right edge. x() does not change. */
- void w(int v) {w_ = v;}
- /*! Change h() by moving the bottom edge. y() does not change. */
- void h(int v) {h_ = v;}
- /*! Change x() without changing r(), by changing the width. */
- void set_x(int v) {w_ -= v-x_; x_ = v;}
- /*! Change y() without changing b(), by changing the height. */
- void set_y(int v) {h_ -= v-y_; y_ = v;}
- /*! Change r() without changing x(), by changine the width. */
- void set_r(int v) {w_ = v-x_;}
- /*! Change b() without changing y(), by changine the height. */
- void set_b(int v) {h_ = v-y_;}
- /*! Set x(), y(), w(), and h() all at once. */
- void set(int x, int y, int w, int h) {x_=x; y_=y; w_=w; h_=h;}
- /*! Sets x, y, w, h so that's it's centered or aligned (if flags!=0) inside
the source r */
- void set (const Rectangle& r, int w, int h, int flags = 0);
- /*! Add \a d to x() without changing r() (it reduces w() by \a d). */
- void move_x(int d) {x_ += d; w_ -= d;}
- /*! Add \a d to y() without changing b() (it reduces h() by \a d). */
- void move_y(int d) {y_ += d; h_ -= d;}
- /*! Add \a d to r() and w(). */
- void move_r(int d) {w_ += d;}
- /*! Add \a d to b() and h(). */
- void move_b(int d) {h_ += d;}
- /*! Move all edges in by \a d. See also Symbol::inset() */
- void inset(int d) {x_ += d; y_ += d; w_ -= 2*d; h_ -= 2*d;}
- /*! Move entire rectangle by given distance in x and y. */
- void move(int dx, int dy) {x_ += dx; y_ += dy;}
- /*! True if w() or h() are less or equal to zero. */
- bool empty() const {return FLTK3_RECT_EMPTY(w_, h_);}
- /*! Same as !empty(), true if w() and h() are both greater than zero. */
- bool not_empty() const {return !FLTK3_RECT_EMPTY(w_, h_);}
- /*! Integer center position. Rounded to the left if w() is odd. */
- int center_x() const {return x_+(w_>>1);}
- /*! Integer center position. Rounded to lower y if h() is odd. */
- int center_y() const {return y_+(h_>>1);}
- /*! Where to put baseline to center current font nicely */
- int baseline_y() const;
-
- Rectangle() {}
-
- /*! Constructor that sets x(), y(), w(), and h(). */
- Rectangle(int x, int y, int w, int h) : x_(x), y_(y), w_(w), h_(h) {}
-
- /*! Constructor that sets x() and y() to zero, and sets w() and h(). */
- Rectangle(int w, int h) : x_(0), y_(0), w_(w), h_(h) {}
-
- /*! Copy constructor. */
- Rectangle(const Rectangle& r) : x_(r.x_),y_(r.y_),w_(r.w_),h_(r.h_) {}
-
- /*! Constructor that calls set(). */
- Rectangle(const Rectangle& r, int w, int h, int flags = 0)
{set(r,w,h,flags);}
-
- /*! True if rectangle contains the pixel who's upper-left corner is at x,y */
- bool contains(int x, int y) const {return x>=x_ && y>=y_ && x<x_+w_ &&
y<y_+h_;}
-
- void merge(const Rectangle& r);
- void intersect(const Rectangle& r);
-
-};
+ int x_, y_, w_, h_;
+
+ public:
+
+ /*! Left edge */
+ int x() const {return x_;}
+ /*! Top edge */
+ int y() const {return y_;}
+ /*! Distance between left and right edges */
+ int w() const {return w_;}
+ /*! Distance between top and bottom edges */
+ int h() const {return h_;}
+ /*! Return x()+w(), the right edge of the rectangle. */
+ int r() const {return x_+w_;}
+ /*! Return y()+h(), the bottom edge of the rectangle. */
+ int b() const {return y_+h_;}
+ /*! Move the rectangle so the left edge is at \a v. */
+ void x(int v) {x_ = v;}
+ /*! Move the rectangle so the top edge is at \a v. */
+ void y(int v) {y_ = v;}
+ /*! Change w() by moving the right edge. x() does not change. */
+ void w(int v) {w_ = v;}
+ /*! Change h() by moving the bottom edge. y() does not change. */
+ void h(int v) {h_ = v;}
+ /*! Change x() without changing r(), by changing the width. */
+ void set_x(int v) {w_ -= v-x_; x_ = v;}
+ /*! Change y() without changing b(), by changing the height. */
+ void set_y(int v) {h_ -= v-y_; y_ = v;}
+ /*! Change r() without changing x(), by changine the width. */
+ void set_r(int v) {w_ = v-x_;}
+ /*! Change b() without changing y(), by changine the height. */
+ void set_b(int v) {h_ = v-y_;}
+ /*! Set x(), y(), w(), and h() all at once. */
+ void set(int x, int y, int w, int h) {x_=x; y_=y; w_=w; h_=h;}
+ /*! Sets x, y, w, h so that's it's centered or aligned (if flags!=0)
inside the source r */
+ void set (const Rectangle& r, int w, int h, int flags = 0);
+ /*! Add \a d to x() without changing r() (it reduces w() by \a d). */
+ void move_x(int d) {x_ += d; w_ -= d;}
+ /*! Add \a d to y() without changing b() (it reduces h() by \a d). */
+ void move_y(int d) {y_ += d; h_ -= d;}
+ /*! Add \a d to r() and w(). */
+ void move_r(int d) {w_ += d;}
+ /*! Add \a d to b() and h(). */
+ void move_b(int d) {h_ += d;}
+ /*! Move all edges in by \a d. See also Symbol::inset() */
+ void inset(int d) {x_ += d; y_ += d; w_ -= 2*d; h_ -= 2*d;}
+ /*! Move entire rectangle by given distance in x and y. */
+ void move(int dx, int dy) {x_ += dx; y_ += dy;}
+ /*! True if w() or h() are less or equal to zero. */
+ bool empty() const {return FLTK3_RECT_EMPTY(w_, h_);}
+ /*! Same as !empty(), true if w() and h() are both greater than zero. */
+ bool not_empty() const {return !FLTK3_RECT_EMPTY(w_, h_);}
+ /*! Integer center position. Rounded to the left if w() is odd. */
+ int center_x() const {return x_+(w_>>1);}
+ /*! Integer center position. Rounded to lower y if h() is odd. */
+ int center_y() const {return y_+(h_>>1);}
+ /*! Where to put baseline to center current font nicely */
+ int baseline_y() const;
+
+ Rectangle() {}
+
+ /*! Constructor that sets x(), y(), w(), and h(). */
+ Rectangle(int x, int y, int w, int h) : x_(x), y_(y), w_(w), h_(h) {}
+
+ /*! Constructor that sets x() and y() to zero, and sets w() and h(). */
+ Rectangle(int w, int h) : x_(0), y_(0), w_(w), h_(h) {}
+
+ /*! Copy constructor. */
+ Rectangle(const Rectangle& r) : x_(r.x_),y_(r.y_),w_(r.w_),h_(r.h_) {}
+
+ /*! Constructor that calls set(). */
+ Rectangle(const Rectangle& r, int w, int h, int flags = 0)
{set(r,w,h,flags);}
+
+ /*! True if rectangle contains the pixel who's upper-left corner is at x,y
*/
+ bool contains(int x, int y) const {return x>=x_ && y>=y_ && x<x_+w_ &&
y<y_+h_;}
+
+ void merge(const Rectangle& r);
+ void intersect(const Rectangle& r);
+
+ /*! True if two rectangles touch or intersect. */
+ bool intersects(const Rectangle& r);
+
+ };
}
Modified: branches/branch-3.0/src/fltk3/MenuWindow.cxx
===================================================================
--- branches/branch-3.0/src/fltk3/MenuWindow.cxx 2012-07-27 22:12:52 UTC
(rev 9647)
+++ branches/branch-3.0/src/fltk3/MenuWindow.cxx 2012-07-28 13:38:18 UTC
(rev 9648)
@@ -119,6 +119,99 @@
}
+//------------------------------------------------------------------------------
+
+
+fltk3::PopupWindow::PopupWindow(int x, int y, int w, int h, const char *title)
+: fltk3::MenuWindow(x, y, w, h, title),
+ pUserPosition(true)
+{
+ set_modal();
+ clear_border();
+ set_menu_window();
+}
+
+
+fltk3::PopupWindow::PopupWindow(int w, int h, const char *title)
+: fltk3::MenuWindow(w, h, title),
+ pUserPosition(false)
+{
+ set_modal();
+ clear_border();
+ set_menu_window();
+}
+
+
+fltk3::PopupWindow::~PopupWindow()
+{
+ hide();
+}
+
+
+void fltk3::PopupWindow::hide_i(fltk3::Widget* w, void *d)
+{
+ fltk3::PopupWindow* p = ((fltk3::PopupWindow*)d);
+ p->pTrigger = w;
+ p->hide();
+}
+
+
+int fltk3::PopupWindow::handle(int e) {
+ fltk3::Widget* wi;
+ switch (e) {
+ case fltk3::KEYBOARD:
+ switch (fltk3::event_key()) {
+ case fltk3::EscapeKey:
+ pTrigger = 0L;
+ hide();
+ return 1;
+ }
+ for (wi = fltk3::focus(); wi; wi = wi->parent()) {
+ if (wi==this) break;
+ if (wi->send(fltk3::KEYBOARD)) return 1;
+ }
+ return 0;
+ case fltk3::SHORTCUT:
+ switch (fltk3::event_key()) {
+ case fltk3::EscapeKey:
+ pTrigger = 0L;
+ hide();
+ return 1;
+ }
+ break;
+ case fltk3::PUSH: {
+ int mx = fltk3::event_x_root();
+ int my = fltk3::event_y_root();
+ if (!Rectangle::contains(mx, my)) {
+ pTrigger = 0L;
+ hide();
+ return 1;
+ }
+ break;
+ }
+ }
+ return MenuWindow::handle(e);
+}
+
+
+fltk3::Widget* fltk3::PopupWindow::popup()
+{
+ pTrigger = 0L;
+ if (!pUserPosition)
+ position(fltk3::event_x_root(), fltk3::event_y_root());
+ show();
+ fltk3::grab(this);
+ for (;;) {
+ fltk3::wait();
+ if (!visible_r())
+ break;
+ }
+ hide();
+ fltk3::grab(0);
+ return pTrigger;
+}
+
+
//
// End of "$Id$".
//
Modified: branches/branch-3.0/src/fltk3/Widget.cxx
===================================================================
--- branches/branch-3.0/src/fltk3/Widget.cxx 2012-07-27 22:12:52 UTC (rev
9647)
+++ branches/branch-3.0/src/fltk3/Widget.cxx 2012-07-28 13:38:18 UTC (rev
9648)
@@ -509,7 +509,13 @@
if (R.b() < b()) set_b(R.b());
}
+bool fltk3::Rectangle::intersects(const fltk3::Rectangle& R) {
+ if (R.x()>r() || R.r()<x()) return false;
+ if (R.y()>b() || R.b()<y()) return false;
+ return true;
+}
+
// Call to->handle(), but first replace the mouse x/y with the correct
// values to account for nested windows. 'window' is the outermost
// window the event was posted to by the system
_______________________________________________
fltk-commit mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk-commit