From 95c5a726a76521eb87ff9122dda9bb8d9818263f Mon Sep 17 00:00:00 2001 From: mfranz Date: Sat, 10 Jan 2009 21:58:26 +0000 Subject: [PATCH] make dialogs resizable with Ctrl-dragging At the moment the dialog grows to North-East. Only dialogs with the flag set to true are resizable. --- src/GUI/dialog.cxx | 82 ++++++++++++++++++++++++++++++++++++++++++---- src/GUI/dialog.hxx | 10 ++++-- src/GUI/layout.cxx | 3 +- 3 files changed, 85 insertions(+), 10 deletions(-) diff --git a/src/GUI/dialog.cxx b/src/GUI/dialog.cxx index 41a967aa1..dad53b3dd 100644 --- a/src/GUI/dialog.cxx +++ b/src/GUI/dialog.cxx @@ -6,6 +6,7 @@ #include #include +#include
#include "dialog.hxx" #include "new_gui.hxx" @@ -87,6 +88,7 @@ struct GUIInfo void apply_format(SGPropertyNode *); FGDialog * dialog; + SGPropertyNode_ptr node; vector bindings; int key; string label, legend, text, format; @@ -190,7 +192,9 @@ puObject *fgPopup::getActiveInputField(puObject *object) */ int fgPopup::checkHit(int button, int updown, int x, int y) { - int result = puPopup::checkHit(button, updown, x, y); + int result = 0; + if (updown != PU_DRAG) + result = puPopup::checkHit(button, updown, x, y); if (!_draggable) return result; @@ -209,13 +213,44 @@ int fgPopup::checkHit(int button, int updown, int x, int y) if (hit & (PUCLASS_BUTTON|PUCLASS_ONESHOT|PUCLASS_INPUT)) return result; - int px, py; - getPosition(&px, &py); + getPosition(&_dlgX, &_dlgY); + getSize(&_dlgW, &_dlgH); + _modifier = fgGetKeyModifiers(); _dragging = true; - _dX = px - x; - _dY = py - y; + _startX = x; + _startY = y; + } else if (updown == PU_DRAG && _dragging) { - setPosition(x + _dX, y + _dY); + if (_modifier & KEYMOD_CTRL) { + if (!_resizable) + return result; + + int w = _dlgW + x - _startX; + int h = _dlgH + y - _startY; + + GUIInfo *info = (GUIInfo *)getUserData(); + if (info && info->node) { + int y = _dlgY; // + _dlgH - h; + int pw, ph; + LayoutWidget wid(info->node); + wid.calcPrefSize(&pw, &ph); + if (w < pw) + w = pw; + if (h < ph) + h = ph; + + // first child is always the dialog background puFrame + getFirstChild()->setSize(w, h); + setSize(w, h); + setPosition(_dlgX, y); + + wid.layout(_dlgX, y, w, h); + applySize(static_cast(this)); + } + } else { + setPosition(x + _dlgX - _startX, y + _dlgY - _startY); + } + } else { _dragging = false; } @@ -241,6 +276,36 @@ int fgPopup::getHitObjects(puObject *object, int x, int y) return type; } +void fgPopup::applySize(puObject *object) +{ + // compound plib widgets use setUserData() for internal purposes, so refuse to + // descend into anything that has more bits set than the following + const int validUserData = PUCLASS_VALUE|PUCLASS_OBJECT|PUCLASS_GROUP|PUCLASS_INTERFACE + |PUCLASS_FRAME|PUCLASS_TEXT|PUCLASS_BUTTON|PUCLASS_ONESHOT|PUCLASS_INPUT + |PUCLASS_ARROW|PUCLASS_DIAL|PUCLASS_POPUP; + + int type = object->getType(); + if (type & PUCLASS_GROUP && !(type & ~validUserData)) + for (puObject *obj = ((puGroup *)object)->getFirstChild(); + obj; obj = obj->getNextObject()) + applySize(obj); + + GUIInfo *info = (GUIInfo *)object->getUserData(); + if (!info) + return; + + SGPropertyNode *n = info->node; + if (!n) { + SG_LOG(SG_GENERAL, SG_ALERT, "applySize: no props"); + return; + } + int x = n->getIntValue("x"); + int y = n->getIntValue("y"); + int w = n->getIntValue("width", 4); + int h = n->getIntValue("height", 4); + object->setPosition(x, y); + object->setSize(w, h); +} //////////////////////////////////////////////////////////////////////// @@ -537,10 +602,11 @@ FGDialog::makeObject (SGPropertyNode * props, int parentWidth, int parentHeight) if (type == "dialog") { puPopup * obj; bool draggable = props->getBoolValue("draggable", true); + bool resizable = props->getBoolValue("resizable", false); if (props->getBoolValue("modal", false)) obj = new puDialogBox(x, y); else - obj = new fgPopup(x, y, draggable); + obj = new fgPopup(x, y, resizable, draggable); setupGroup(obj, props, width, height, true); setColor(obj, props); return obj; @@ -560,6 +626,7 @@ FGDialog::makeObject (SGPropertyNode * props, int parentWidth, int parentHeight) } else if (type == "hrule" || type == "vrule") { puFrame * obj = new puFrame(x, y, x + width, y + height); obj->setBorderThickness(0); + setupObject(obj, props); setColor(obj, props, BACKGROUND|FOREGROUND|HIGHLIGHT); return obj; @@ -697,6 +764,7 @@ FGDialog::setupObject (puObject * object, SGPropertyNode * props) _info.push_back(info); object->setLabelPlace(PUPLACE_CENTERED_RIGHT); object->makeReturnDefault(props->getBoolValue("default")); + info->node = props; if (props->hasValue("legend")) { info->legend = props->getStringValue("legend"); diff --git a/src/GUI/dialog.hxx b/src/GUI/dialog.hxx index 09b76232f..f9fb4227f 100644 --- a/src/GUI/dialog.hxx +++ b/src/GUI/dialog.hxx @@ -175,16 +175,22 @@ private: // class fgPopup : public puPopup { public: - fgPopup(int x, int y, bool d = true) : puPopup(x, y) { _dragging = false; _draggable = d;} + fgPopup(int x, int y, bool r = true, bool d = true) : + puPopup(x, y), _draggable(d), _resizable(r), _dragging(false) + {} int checkHit(int b, int up, int x, int y); int checkKey(int key, int updown); int getHitObjects(puObject *, int x, int y); puObject *getKeyObject(puObject *, int key); puObject *getActiveInputField(puObject *); + void applySize(puObject *); private: bool _draggable; + bool _resizable; bool _dragging; - int _dX, _dY; + int _modifier; + int _dlgX, _dlgY, _dlgW, _dlgH; + int _startX, _startY; }; diff --git a/src/GUI/layout.cxx b/src/GUI/layout.cxx index aeec747c6..5bfd35243 100644 --- a/src/GUI/layout.cxx +++ b/src/GUI/layout.cxx @@ -72,7 +72,8 @@ void LayoutWidget::calcPrefSize(int* w, int* h) *w = *h = 17*UNIT; if(getBool("vertical")) *w = 4*UNIT; else *h = 4*UNIT; - } else if (isType("list") || isType("airport-list") || isType("dial")) { + } else if (isType("list") || isType("airport-list") + || isType("property-list") || isType("dial")) { *w = *h = 12*UNIT; } else if (isType("hrule")) { *h = 1;