diff --git a/ChangeLog b/ChangeLog index 20dcc3ce..0a1789fe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2016-06-12 Markus Gans + * Add a title bar menu to close dialogs + 2016-05-24 Markus Gans * Use nl_langinfo to determine the numeric thousands separator for Fstring::setFormatedNumber as default parameter diff --git a/doc/TODO b/doc/TODO index b63364ce..cc20dadc 100644 --- a/doc/TODO +++ b/doc/TODO @@ -20,8 +20,6 @@ Missing Features └──► tmp --------------------------------------- -- A single click on the FDialog title button [-] should open - a FMenu with a closing item - FDialog title button [▲] and [▼] should maximized or restore the window size on a resizeable dialog - A possibility to change the window size dynamically with the mouse diff --git a/src/fapp.cpp b/src/fapp.cpp index 1bc028de..8c0ddb86 100644 --- a/src/fapp.cpp +++ b/src/fapp.cpp @@ -969,7 +969,7 @@ void FApplication::processMouseEvent() } } - // close open menu + // close the open menu if ( open_menu && ! b_state.mouse_moved ) { FMenu* menu = static_cast(open_menu); @@ -980,8 +980,6 @@ void FApplication::processMouseEvent() menu->hide(); menu->hideSubMenus(); menu->hideSuperMenus(); - if ( statusBar() ) - statusBar()->clearMessage(); // No widget was been clicked if ( ! clicked_widget ) @@ -1375,7 +1373,9 @@ bool FApplication::sendEvent(FObject* receiver, FEvent* event) window = FWindow::getWindowWidget(widget); // block events for widgets in non modal windows - if ( window && (window->getFlags() & fc::modal) == 0 ) + if ( window + && (window->getFlags() & fc::modal) == 0 + && ! window->isMenu() ) { switch ( event->type() ) { diff --git a/src/fdialog.cpp b/src/fdialog.cpp index 906cb79e..147e27c5 100644 --- a/src/fdialog.cpp +++ b/src/fdialog.cpp @@ -20,6 +20,8 @@ FDialog::FDialog(FWidget* parent) , TitleBarClickPos() , oldGeometry() , focus_widget(0) + , dialog_menu() + , dgl_menuitem() { init(); } @@ -33,6 +35,8 @@ FDialog::FDialog (const FString& txt, FWidget* parent) , TitleBarClickPos() , oldGeometry() , focus_widget(0) + , dialog_menu() + , dgl_menuitem() { init(); } @@ -88,12 +92,13 @@ FDialog::~FDialog() // destructor //---------------------------------------------------------------------- void FDialog::init() { + FWidget* rootObj = getRootWidget(); + xmin = 1 + rootObj->getLeftPadding(); + ymin = 1 + rootObj->getTopPadding(); + xmax = rootObj->getWidth(); + ymax = rootObj->getHeight(); width = 10; height = 10; - xmin = 1; - ymin = 1; - xmax = width; - ymax = height; client_xmin = 1; client_ymin = 1; client_xmax = width; @@ -106,6 +111,7 @@ void FDialog::init() setGeometry (1, 1, 10, 10, false); // initialize geometry values ignore_padding = true; window_object = true; + dialog_object = true; addWindow(this); setActiveWindow(this); @@ -124,6 +130,25 @@ void FDialog::init() old_focus->redraw(); } accelerator_list = new Accelerators(); + + dialog_menu = new FMenu ("-", this); + dialog_menu->move (xpos, ypos+1); + + dgl_menuitem = dialog_menu->getItem(); + if ( dgl_menuitem ) + { + dgl_menuitem->ignorePadding(); + dgl_menuitem->unsetFocusable(); + } + + FMenuItem* close_item = new FMenuItem ("&Close", dialog_menu); + close_item->setStatusbarMessage ("Close window"); + + close_item->addCallback + ( + "clicked", + _METHOD_CALLBACK (this, &FDialog::cb_close) + ); } //---------------------------------------------------------------------- @@ -214,14 +239,28 @@ void FDialog::drawTitleBar() print (fc::NF_rev_menu_button3); } else if ( isMonochron() ) - print ("[-]"); + { + print ('['); + if ( dgl_menuitem ) + print (dgl_menuitem->getText()); + else + print ('-'); + print (']'); + } else - print (" - "); + { + print (' '); + if ( dgl_menuitem ) + print (dgl_menuitem->getText()); + else + print ('-'); + print (' '); + } // fill with spaces (left of the title) if ( getMaxColor() < 16 ) setBold(); - if ( isActiveWindow() ) + if ( isActiveWindow() || dialog_menu->isVisible() ) setColor (wc.titlebar_active_fg, wc.titlebar_active_bg); else setColor (wc.titlebar_inactive_fg, wc.titlebar_inactive_bg); @@ -251,6 +290,17 @@ void FDialog::drawTitleBar() } +//---------------------------------------------------------------------- +void FDialog::cb_close (FWidget*, void*) +{ + dialog_menu->unselectItem(); + dialog_menu->hide(); + setClickedWidget(0); + drawTitleBar(); + close(); +} + + // protected methods of FDialog //---------------------------------------------------------------------- void FDialog::done(int result) @@ -475,6 +525,47 @@ void FDialog::onMouseDown (FMouseEvent* ev) } if ( has_raised ) redraw(); + + // click on titlebar menu button + if ( mouse_x < 4 && mouse_y == 1 ) + { + if ( dialog_menu->isVisible() ) + { + dialog_menu->unselectItem(); + dialog_menu->hide(); + activateWindow(); + raiseWindow(); + getFocusWidget()->setFocus(); + redraw(); + if ( statusBar() ) + statusBar()->drawMessage(); + } + else + { + setOpenMenu(dialog_menu); + dialog_menu->move (xpos, ypos+1); + dialog_menu->setVisible(); + dialog_menu->show(); + dialog_menu->raiseWindow(dialog_menu); + dialog_menu->redraw(); + } + } + } + else // ev->getButton() != fc::LeftButton + { + // click on titlebar menu button + if ( mouse_x < 4 && mouse_y == 1 && dialog_menu->isVisible() ) + { + // close menu + dialog_menu->unselectItem(); + dialog_menu->hide(); + activateWindow(); + raiseWindow(); + getFocusWidget()->setFocus(); + redraw(); + if ( statusBar() ) + statusBar()->drawMessage(); + } } if ( ev->getButton() == fc::RightButton ) @@ -537,6 +628,9 @@ void FDialog::onMouseUp (FMouseEvent* ev) if ( ev->getButton() == fc::LeftButton ) { + int mouse_x = ev->getX(); + int mouse_y = ev->getY(); + if ( ! TitleBarClickPos.isNull() && titlebar_x > xpos+xmin+2 && titlebar_x < xpos+xmin+width @@ -547,6 +641,24 @@ void FDialog::onMouseUp (FMouseEvent* ev) move (currentPos + deltaPos); TitleBarClickPos = ev->getGlobalPos(); } + + // click on titlebar menu button + if ( mouse_x < 4 + && mouse_y == 1 + && dialog_menu->isVisible() + && ! dialog_menu->hasSelectedItem() ) + { + FMenuItem* first_item; + dialog_menu->selectFirstItem(); + first_item = dialog_menu->getSelectedItem(); + if ( first_item ) + first_item->setFocus(); + dialog_menu->redraw(); + if ( statusBar() ) + statusBar()->drawMessage(); + updateTerminal(); + flush_out(); + } } } @@ -562,6 +674,25 @@ void FDialog::onMouseMove (FMouseEvent* ev) move (currentPos + deltaPos); TitleBarClickPos = ev->getGlobalPos(); } + + if ( dialog_menu->isVisible() && dialog_menu->isShown() ) + { + // Mouse event handover to the menu + const FRect& menu_geometry = dialog_menu->getGeometryGlobal(); + + if ( dialog_menu->count() > 0 + && menu_geometry.contains(ev->getGlobalPos()) ) + { + const FPoint& g = ev->getGlobalPos(); + const FPoint& p = dialog_menu->globalToLocalPos(g); + int b = ev->getButton(); + FMouseEvent* _ev = new FMouseEvent (fc::MouseMove_Event, p, g, b); + dialog_menu->mouse_down = true; + setClickedWidget(dialog_menu); + dialog_menu->onMouseMove(_ev); + delete _ev; + } + } } } @@ -580,8 +711,14 @@ void FDialog::onMouseDoubleClick (FMouseEvent* ev) FPoint gPos = ev->getGlobalPos(); if ( title_button.contains(gPos) ) { + dialog_menu->unselectItem(); + dialog_menu->hide(); setClickedWidget(0); - close(); + + if ( isModal() ) + done(FDialog::Reject); + else + close(); } } @@ -591,18 +728,15 @@ void FDialog::onWindowActive (FEvent*) if ( isVisible() && isShown() ) drawTitleBar(); - if ( ! FWidget::getFocusWidget() ) + if ( focus_widget && focus_widget->isVisible() && focus_widget->isShown() ) { - if ( focus_widget && focus_widget->isVisible() && focus_widget->isShown() ) - { - focus_widget->setFocus(); - focus_widget->redraw(); - if ( statusBar() ) - statusBar()->drawMessage(); - } - else - focusFirstChild(); + focus_widget->setFocus(); + focus_widget->redraw(); + if ( statusBar() ) + statusBar()->drawMessage(); } + else + focusFirstChild(); } //---------------------------------------------------------------------- diff --git a/src/fdialog.h b/src/fdialog.h index 9f127259..74f5e2f0 100644 --- a/src/fdialog.h +++ b/src/fdialog.h @@ -28,6 +28,8 @@ #ifndef _FDIALOG_H #define _FDIALOG_H +#include "fmenu.h" +#include "fmenuitem.h" #include "fwindow.h" @@ -48,12 +50,14 @@ class FDialog : public FWindow }; private: - FString tb_text; // title bar text - int result_code; - bool maximized; - FPoint TitleBarClickPos; - FRect oldGeometry; // required by move() - FWidget* focus_widget; + FString tb_text; // title bar text + int result_code; + bool maximized; + FPoint TitleBarClickPos; + FRect oldGeometry; // required by move() + FWidget* focus_widget; + FMenu* dialog_menu; + FMenuItem* dgl_menuitem; private: FDialog (const FDialog&); @@ -61,6 +65,7 @@ class FDialog : public FWindow void init(); void drawBorder(); void drawTitleBar(); + void cb_close (FWidget*, void*); protected: virtual void done (int); diff --git a/src/fmenu.h b/src/fmenu.h index 7484ba1b..25ba4f2c 100644 --- a/src/fmenu.h +++ b/src/fmenu.h @@ -130,6 +130,7 @@ class FMenu : public FWindow, public FMenuList private: friend class FApplication; friend class FCheckMenuItem; + friend class FDialog; friend class FMenuBar; friend class FMenuItem; friend class FRadioMenuItem; diff --git a/src/fmenuitem.cpp b/src/fmenuitem.cpp index dee4cc78..6e66c06f 100644 --- a/src/fmenuitem.cpp +++ b/src/fmenuitem.cpp @@ -2,6 +2,7 @@ // Provides: class FMenuItem #include "fapp.h" +#include "fdialog.h" #include "fmenu.h" #include "fmenubar.h" #include "fmenulist.h" @@ -246,6 +247,12 @@ void FMenuItem::processClicked() // protected methods of FMenuItem +//---------------------------------------------------------------------- +bool FMenuItem::isWindowsMenu (FWidget* w) const +{ + return w->isDialog(); +} + //---------------------------------------------------------------------- bool FMenuItem::isMenuBar (FWidget* w) const { @@ -369,6 +376,52 @@ void FMenuItem::onKeyPress (FKeyEvent* ev) } } +//---------------------------------------------------------------------- +void FMenuItem::onMouseDoubleClick (FMouseEvent* ev) +{ + if ( super_menu ) + { + const FPoint& g = ev->getGlobalPos(); + int b = ev->getButton(); + + if ( isMenu(super_menu) ) + { + FMenu* smenu = dynamic_cast(super_menu); + if ( smenu ) + { + const FPoint& p2 = smenu->globalToLocalPos(g); + FMouseEvent* _ev = new FMouseEvent (fc::MouseDoubleClick_Event, p2, g, b); + smenu->onMouseDoubleClick(_ev); + delete _ev; + } + } + + if ( isMenuBar(super_menu) ) + { + FMenuBar* mbar = dynamic_cast(super_menu); + if ( mbar ) + { + const FPoint& p2 = mbar->globalToLocalPos(g); + FMouseEvent* _ev = new FMouseEvent (fc::MouseDoubleClick_Event, p2, g, b); + mbar->onMouseDoubleClick(_ev); + delete _ev; + } + } + + if ( isWindowsMenu(super_menu) ) + { + FDialog* dgl = dynamic_cast(super_menu); + if ( dgl ) + { + const FPoint& p2 = dgl->globalToLocalPos(g); + FMouseEvent* _ev = new FMouseEvent (fc::MouseDoubleClick_Event, p2, g, b); + dgl->onMouseDoubleClick(_ev); + delete _ev; + } + } + } +} + //---------------------------------------------------------------------- void FMenuItem::onMouseDown (FMouseEvent* ev) { @@ -400,6 +453,18 @@ void FMenuItem::onMouseDown (FMouseEvent* ev) delete _ev; } } + + if ( isWindowsMenu(super_menu) ) + { + FDialog* dgl = dynamic_cast(super_menu); + if ( dgl ) + { + const FPoint& p2 = dgl->globalToLocalPos(g); + FMouseEvent* _ev = new FMouseEvent (fc::MouseDown_Event, p2, g, b); + dgl->onMouseDown(_ev); + delete _ev; + } + } } } @@ -434,6 +499,18 @@ void FMenuItem::onMouseUp (FMouseEvent* ev) delete _ev; } } + + if ( isWindowsMenu(super_menu) ) + { + FDialog* dgl = dynamic_cast(super_menu); + if ( dgl ) + { + const FPoint& p2 = dgl->globalToLocalPos(g); + FMouseEvent* _ev = new FMouseEvent (fc::MouseUp_Event, p2, g, b); + dgl->onMouseUp(_ev); + delete _ev; + } + } } } @@ -469,6 +546,17 @@ void FMenuItem::onMouseMove (FMouseEvent* ev) } } + if ( isWindowsMenu(super_menu) ) + { + FDialog* dgl = dynamic_cast(super_menu); + if ( dgl ) + { + const FPoint& p2 = dgl->globalToLocalPos(g); + FMouseEvent* _ev = new FMouseEvent (fc::MouseMove_Event, p2, g, b); + dgl->onMouseMove(_ev); + delete _ev; + } + } } } diff --git a/src/fmenuitem.h b/src/fmenuitem.h index 11e9877b..df82cc66 100644 --- a/src/fmenuitem.h +++ b/src/fmenuitem.h @@ -65,6 +65,7 @@ class FMenuItem : public FWidget virtual void processClicked(); protected: + bool isWindowsMenu (FWidget*) const; bool isMenuBar (FWidget*) const; bool isMenu (FWidget*) const; FWidget* getSuperMenu() const; @@ -88,6 +89,7 @@ class FMenuItem : public FWidget using FWidget::delAccelerator; void delAccelerator (FWidget*); void onKeyPress (FKeyEvent*); + void onMouseDoubleClick (FMouseEvent*); void onMouseDown (FMouseEvent*); void onMouseUp (FMouseEvent*); void onMouseMove (FMouseEvent*); diff --git a/src/fwidget.cpp b/src/fwidget.cpp index b38a63d1..343e5d9c 100644 --- a/src/fwidget.cpp +++ b/src/fwidget.cpp @@ -54,6 +54,7 @@ FWidget::FWidget (FWidget* parent) , adjustWidgetSizeGlobalShadow() , ignore_padding(false) , window_object(false) + , dialog_object(false) , menu_object(false) , flags(0) , foregroundColor() diff --git a/src/fwidget.h b/src/fwidget.h index c942ce03..c1bc0ad3 100644 --- a/src/fwidget.h +++ b/src/fwidget.h @@ -246,6 +246,7 @@ class FWidget : public FObject, public FTerm FRect adjustWidgetSizeGlobalShadow; bool ignore_padding; bool window_object; + bool dialog_object; bool menu_object; int flags; short foregroundColor; @@ -331,6 +332,7 @@ class FWidget : public FObject, public FTerm FWidget* parentWidget() const; bool isRootWidget() const; bool isWindow() const; + bool isDialog() const; bool isMenu() const; virtual bool close(); @@ -580,6 +582,10 @@ inline bool FWidget::isShown() const inline bool FWidget::isWindow() const { return window_object; } +//---------------------------------------------------------------------- +inline bool FWidget::isDialog() const +{ return dialog_object; } + //---------------------------------------------------------------------- inline bool FWidget::isMenu() const { return menu_object; }