//============================================================================= // // File : KvsObject_popupMenu.cpp // Creation date : Fri Mar 18 21:30:48 CEST 2005 // by Tonino Imbesi(Grifisx) and Alessandro Carbone(Noldor) // // This file is part of the KVIrc IRC client distribution // Copyright (C) 2005-2008 Alessandro Carbone (elfonol at gmail dot com) // // This program is FREE software. You can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the HOPE that it will be USEFUL, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, write to the Free Software Foundation, // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // //============================================================================= #include "KvsObject_popupMenu.h" #include "KviError.h" #include "kvi_debug.h" #include "KviLocale.h" #include "KviIconManager.h" #include #include #include /* @doc: popupmenu @keyterms: popupmenu object class, @title: popupmenu class @type: class @short: Provides a popup menu. @inherits: [class]object[/class] [class]widget[/class] @description: This widget can be used to display a popup menu. Technically, a popup menu consists of a list of menu items.[br] You add items with insertItem(). An item can be a string. In addition, items can have an optional icon drawn on the very left side.[br] @functions: !fn: $insertItem(,[icon_id:string]) Inserts menu items into a popup menu with optional icon and return the popup identifier. !fn: $addMenu() Sets the popupmenu title to text. !fn: $exec([,,]) If called without paramaters show the popup menu at the current pointer position.[br] With the optional parameters show the popup menu at the coordinate x,y widget parameter relative. !fn: $removeItem() Removes the menu item that has the identifier ID. !fn: $removeItemAt() Removes the menu item at position index. !fn: $insertSeparator() Inserts a separator at position index.[br] If the index is negative the separator becomes the last menu item. !fn: $activatedEvent() This function is called when a menu item and return the the item ID.[br] The default implementation emits the [classfnc]$activated[/classfnc]() signal. !fn: $highligthtedEvent() This function is called when a menu item is highlighted (hovered) and return the item ID.[br] The default implementation emits the [classfnc]$highlighted[/classfnc]() signal. @signals: !sg: $activated() This signal is emitted by the default implementation of [classfnc]$activatedEvent[/classfnc](). !sg: $highlighted() This signal is emitted by the default implementation of [classfnc]$highlightedEvent[/classfnc](). [br] @examples: [example] [comment]# First we define a class inherited from popupmenu[/comment] class(menu,popupmenu) { constructor() { [comment]# We store the item's ID for checking in activatedEvent[/comment] @%tile_id=@$insertItem("Tile",118) @%cascade_id=@$insertItem("Cascade",115) @$insertSeparator(3) @%closeactw_id=@$insertItem("Close Active Window",08) @%closeallw_id=@$insertItem("Close All Window",58) } activatedEvent() { [comment]# Now we emit a signals to the relative to the user choice[/comment] %id=$0 if (%id==@%tile_id) @$emit("tile") else if(%id==@%cascade_id) @$emit("cascade") else if (%id==@%closeactw_id) @$emit("closeactive") else @$emit("closeallwindows") [comment]# Deleting the popup[/comment] delete $$ } } class (ws,widget)[br] { [comment]In the constructor we create everything that belong to the single widget.[/comment] constructor() { [comment]# Here we generate a loop to create our labels inside the widget.[/comment] %lay=$new(layout,$$) [comment]we use a vbox to managing labels in vertical orientation[/comment] %vb=$new(vbox,$$) [comment]# Then add the vbox to the main layout[/comment] %lay->$addWidget(%vb,0,0) [comment]# Let's create our colorful labels[/comment] for(%i=0;%i<15;%i++) { @%label=$new(label,%vb) @%label->$settext("Another class by N\&G") [comment]# We set our foreground's colors using the hex array in a random way.[/comment] @%label->$setforegroundcolor($array($rand(255),$rand(255),$rand(255))) } } customContextMenuRequestedEvent() { [comment]# We create the popupmenu relative to this widget at runtime.[/comment] %p=$new(menu,$$) objects.connect %p tile @$parent tile objects.connect %p cascade @$parent cascade objects.connect %p closeactive @$parent closeactivewindow objects.connect %p closeallwindows @$parent closeallwindows %p->$exec($$,$($0+10),$($1+10)) } } [comment]# We create the workspace widget[/comment] %Workspace=$new(workspace) [comment]# We use as space as we have[/comment] %size[]=%Workspace->$screenResolution() [comment]# Resize it[/comment] %Workspace->$resize(%size[0],%size[1]) [comment]# Then create 20 subwidget[/comment] for(%i=0;%i<20;%i++) { %w=$new(ws,%Workspace) [comment]# Let's add every widget to the workspace[/comment] %Workspace->$addSubWindow(%w) [comment]# Then "shake it" a little bit around :-)[/comment] %w->$move($rand($(%size[0]-50)),$rand($(%size[1]-50))) } [comment]# Reimplement closeEvent to delete all this :-)[/comment] privateimpl(%Workspace,closeEvent) { delete $$ } [comment]# Let's show![/comment] %Workspace->$show() [/example] */ static QHash actionsDict; static int iIdentifier = 0; static int addActionToDict(QAction * pAction) { actionsDict.insert(iIdentifier, pAction); iIdentifier++; return (iIdentifier - 1); } static void removeMenuAllActions(QMenu * pMenu) { QList pActionsList = pMenu->actions(); QList pActionsListDictValues = actionsDict.values(); for(int i = 0; i < pActionsList.count(); i++) { int iIdx = pActionsListDictValues.indexOf(pActionsList.at(i)); if(iIdx >= 0) actionsDict.remove(actionsDict.key(pActionsList.at(i))); } } static QAction * getAction(int idx) { return actionsDict.value(idx); } static void removeAction(int idx) { actionsDict.remove(idx); } KVSO_BEGIN_REGISTERCLASS(KvsObject_popupMenu, "popupmenu", "widget") KVSO_REGISTER_HANDLER_BY_NAME(KvsObject_popupMenu, insertItem) KVSO_REGISTER_HANDLER_BY_NAME(KvsObject_popupMenu, setTitle) KVSO_REGISTER_HANDLER_BY_NAME(KvsObject_popupMenu, exec) KVSO_REGISTER_HANDLER_BY_NAME(KvsObject_popupMenu, insertSeparator) KVSO_REGISTER_HANDLER_BY_NAME(KvsObject_popupMenu, removeItem) KVSO_REGISTER_HANDLER_BY_NAME(KvsObject_popupMenu, addMenu) // events KVSO_REGISTER_HANDLER_BY_NAME(KvsObject_popupMenu, highlightedEvent) KVSO_REGISTER_HANDLER_BY_NAME(KvsObject_popupMenu, activatedEvent) KVSO_END_REGISTERCLASS(KvsObject_popupMenu) KVSO_BEGIN_CONSTRUCTOR(KvsObject_popupMenu, KvsObject_widget) KVSO_END_CONSTRUCTOR(KvsObject_popupMenu) KVSO_BEGIN_DESTRUCTOR(KvsObject_popupMenu) KVSO_END_DESTRUCTOR(KvsObject_popupMenu) bool KvsObject_popupMenu::init(KviKvsRunTimeContext *, KviKvsVariantList *) { SET_OBJECT(QMenu) connect(widget(), SIGNAL(triggered(QAction *)), this, SLOT(slottriggered(QAction *))); connect(widget(), SIGNAL(destroyed(QObject *)), this, SLOT(aboutToDie(QObject *))); connect(widget(), SIGNAL(hovered(QAction *)), this, SLOT(slothovered(QAction *))); return true; } KVSO_CLASS_FUNCTION(popupMenu, insertItem) { CHECK_INTERNAL_POINTER(widget()) QString szItem, szIcon; KVSO_PARAMETERS_BEGIN(c) KVSO_PARAMETER("text", KVS_PT_STRING, 0, szItem) KVSO_PARAMETER("icon_id", KVS_PT_STRING, KVS_PF_OPTIONAL, szIcon) KVSO_PARAMETERS_END(c) QPixmap * pix = nullptr; QAction * pAction = nullptr; if(!szIcon.isEmpty()) { pix = g_pIconManager->getImage(szIcon); if(pix) pAction = ((QMenu *)widget())->addAction(*pix, szItem); else c->warning(__tr2qs_ctx("Icon '%Q' doesn't exist", "objects"), &szIcon); } else pAction = ((QMenu *)widget())->addAction(szItem); int identifier = addActionToDict(pAction); c->returnValue()->setInteger((kvs_int_t)identifier); return true; } KVSO_CLASS_FUNCTION(popupMenu, setTitle) { QString szTitle; KVSO_PARAMETERS_BEGIN(c) KVSO_PARAMETER("title", KVS_PT_STRING, 0, szTitle) KVSO_PARAMETERS_END(c) if(!widget()) return true; ((QMenu *)widget())->setTitle(szTitle); return true; } KVSO_CLASS_FUNCTION(popupMenu, exec) { CHECK_INTERNAL_POINTER(widget()) if(!c->params()->count()) { ((QMenu *)widget())->exec(QCursor::pos()); return true; } KviKvsObject * pObject; kvs_uint_t iX, iY; QString szLabel, szIcon; kvs_hobject_t hObject; KVSO_PARAMETERS_BEGIN(c) KVSO_PARAMETER("widget", KVS_PT_HOBJECT, 0, hObject) KVSO_PARAMETER("x", KVS_PT_UNSIGNEDINTEGER, 0, iX) KVSO_PARAMETER("y", KVS_PT_UNSIGNEDINTEGER, 0, iY) KVSO_PARAMETERS_END(c) pObject = KviKvsKernel::instance()->objectController()->lookupObject(hObject); CHECK_HOBJECT_IS_WIDGET(pObject) ((QMenu *)widget())->exec(((QWidget *)(pObject->object()))->mapToGlobal(QPoint(iX, iY))); return true; } KVSO_CLASS_FUNCTION(popupMenu, addMenu) { CHECK_INTERNAL_POINTER(widget()) KviKvsObject * pObject; kvs_uint_t iIdx; kvs_hobject_t hObject; KVSO_PARAMETERS_BEGIN(c) KVSO_PARAMETER("popupmenu", KVS_PT_HOBJECT, 0, hObject) KVSO_PARAMETER("index", KVS_PT_UNSIGNEDINTEGER, KVS_PF_OPTIONAL, iIdx) KVSO_PARAMETERS_END(c) pObject = KviKvsKernel::instance()->objectController()->lookupObject(hObject); if(!pObject) { c->warning(__tr2qs_ctx("Popup menu parameter is not an object", "objects")); return true; } if(!pObject->object()) { c->warning(__tr2qs_ctx("Popup menu parameter is not a valid object", "objects")); return true; } if(!pObject->inheritsClass("popupmenu")) { c->warning(__tr2qs_ctx("Popupmenu object required", "objects")); return true; } QAction * pAction; if(iIdx) { QAction * pActionBefore = actionsDict[iIdx]; pAction = ((QMenu *)widget())->insertMenu(pActionBefore, (QMenu *)pObject->object()); } else { pAction = ((QMenu *)widget())->addMenu((QMenu *)pObject->object()); } int identifier = addActionToDict(pAction); c->returnValue()->setInteger((kvs_int_t)identifier); identifier++; return true; } KVSO_CLASS_FUNCTION(popupMenu, removeItem) { CHECK_INTERNAL_POINTER(widget()) kvs_int_t iIdx; KVSO_PARAMETERS_BEGIN(c) KVSO_PARAMETER("item_id", KVS_PT_INTEGER, 0, iIdx) KVSO_PARAMETERS_END(c) QAction * pAction = getAction(iIdx); if(pAction) { ((QMenu *)widget())->removeAction(pAction); removeAction(iIdx); } return true; } KVSO_CLASS_FUNCTION(popupMenu, insertSeparator) { CHECK_INTERNAL_POINTER(widget()) kvs_uint_t iIndex; KVSO_PARAMETERS_BEGIN(c) KVSO_PARAMETER("index", KVS_PT_UNSIGNEDINTEGER, 0, iIndex) KVSO_PARAMETERS_END(c) QAction * pAction = getAction(iIndex); if(pAction) ((QMenu *)widget())->insertSeparator(pAction); return true; } void KvsObject_popupMenu::slothovered(QAction * a) { QHashIterator i(actionsDict); bool bFound = false; while(i.hasNext()) { i.next(); if(i.value() == a) { bFound = true; break; } } // check if the action was created inside this class if(bFound) { KviKvsVariantList params(new KviKvsVariant((kvs_int_t)i.key())); callFunction(this, "highlightedEvent", ¶ms); } } void KvsObject_popupMenu::aboutToDie(QObject * pObject) { qDebug("Removing popup from KVS dict"); removeMenuAllActions((QMenu *)pObject); } KVSO_CLASS_FUNCTION(popupMenu, highlightedEvent) { emitSignal("highlighted", c, c->params()); return true; } void KvsObject_popupMenu::slottriggered(QAction * a) { QHashIterator i(actionsDict); bool bFound = false; while(i.hasNext()) { i.next(); if(i.value() == a) { bFound = true; break; } } // check if the action was created inside this class if(bFound) { KviKvsVariantList params(new KviKvsVariant((kvs_int_t)i.key())); callFunction(this, "activatedEvent", ¶ms); } } KVSO_CLASS_FUNCTION(popupMenu, activatedEvent) { emitSignal("activated", c, c->params()); return true; }