Commit 8a3513c0 authored by Olivier Teulière's avatar Olivier Teulière

* skins2: support for custom popup menus, and win32 implementation.

   XML example:
       <PopupMenu id="sample_menu">
           <MenuItem label="Play" action="vlc.play()" />
           <MenuItem label="Pause" action="vlc.pause()" />
           <MenuSeparator />
           <MenuItem label="Show playlist" action="playlist_window.show()" />
           <MenuItem label="Hide playlist" action="playlist_window.hide()" />
           <MenuSeparator />
           <MenuItem label="Quick open file" action="dialogs.fileSimple()" />
       </PopupMenu>

   To call the menu:
       <Button action="sample_menu.show()" ... />

   Known bug: the popup disappears when the user clicks "too fast" on the
   button: the control refreshes itself in an asynchronous way, and the popup
   dislikes it... so click slowly :)
parent 646896fb
......@@ -61,13 +61,14 @@ SOURCES_skins2 = \
controls/ctrl_video.hpp \
\
events/evt_enter.hpp \
events/evt_generic.hpp \
events/evt_focus.hpp \
events/evt_generic.hpp \
events/evt_input.cpp \
events/evt_input.hpp \
events/evt_key.cpp \
events/evt_key.hpp \
events/evt_leave.hpp \
events/evt_menu.hpp \
events/evt_motion.hpp \
events/evt_mouse.cpp \
events/evt_mouse.hpp \
......@@ -116,9 +117,12 @@ SOURCES_skins2 = \
src/os_factory.hpp \
src/os_graphics.hpp \
src/os_loop.hpp \
src/os_popup.hpp \
src/os_timer.hpp \
src/os_window.hpp \
src/os_tooltip.hpp \
src/popup.cpp \
src/popup.hpp \
src/scaled_bitmap.cpp \
src/scaled_bitmap.hpp \
src/skin_main.cpp \
......@@ -183,6 +187,8 @@ SOURCES_skins2 = \
win32/win32_graphics.hpp \
win32/win32_loop.cpp \
win32/win32_loop.hpp \
win32/win32_popup.cpp \
win32/win32_popup.hpp \
win32/win32_timer.cpp \
win32/win32_timer.hpp \
win32/win32_tooltip.cpp \
......@@ -200,6 +206,8 @@ SOURCES_skins2 = \
x11/x11_graphics.hpp \
x11/x11_loop.cpp \
x11/x11_loop.hpp \
x11/x11_popup.cpp \
x11/x11_popup.hpp \
x11/x11_timer.cpp \
x11/x11_timer.hpp \
x11/x11_window.cpp \
......@@ -215,6 +223,8 @@ SOURCES_skins2 = \
macosx/macosx_graphics.hpp \
macosx/macosx_loop.cpp \
macosx/macosx_loop.hpp \
macosx/macosx_popup.cpp \
macosx/macosx_popup.hpp \
macosx/macosx_timer.cpp \
macosx/macosx_timer.hpp \
macosx/macosx_window.cpp \
......
......@@ -26,8 +26,10 @@
#define CMD_SHOW_WINDOW_HPP
#include "cmd_generic.hpp"
#include "../src/os_factory.hpp"
#include "../src/top_window.hpp"
#include "../src/window_manager.hpp"
#include "../src/popup.hpp"
/// Command to show a window
......@@ -95,4 +97,30 @@ class CmdRaiseAll: public CmdGeneric
WindowManager &m_rWinManager;
};
/// Command to show a popup menu
class CmdShowPopup: public CmdGeneric
{
public:
CmdShowPopup( intf_thread_t *pIntf, Popup &rPopup ):
CmdGeneric( pIntf ), m_rPopup( rPopup ) {}
virtual ~CmdShowPopup() {}
/// This method does the real job of the command
virtual void execute()
{
int x, y;
OSFactory::instance( getIntf() )->getMousePos( x, y );
m_rPopup.show( x, y );
}
/// Return the type of the command
virtual string getType() const { return "show popup"; }
private:
/// Reference to the popup
Popup &m_rPopup;
};
#endif
/*****************************************************************************
* evt_menu.hpp
*****************************************************************************
* Copyright (C) 2003 the VideoLAN team
* $Id:$
*
* Authors: Olivier Teulière <ipkiss@via.ecp.fr>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
#ifndef EVT_MENU_HPP
#define EVT_MENU_HPP
#include "evt_generic.hpp"
/// Mouse move event
class EvtMenu: public EvtGeneric
{
public:
EvtMenu( intf_thread_t *pIntf, int itemId ):
EvtGeneric( pIntf ), m_itemId( itemId ) {}
virtual ~EvtMenu() {}
/// Return the type of event
virtual const string getAsString() const { return "menu"; }
// Getter
int getItemId() const { return m_itemId; }
private:
/// Coordinates of the mouse (absolute or relative)
int m_itemId;
};
#endif
......@@ -45,9 +45,11 @@ class EvtMotion: public EvtInput
private:
/// Coordinates of the mouse (absolute or relative)
/// The coordinates are absolute when the event is sent to the
/// GenericWindow, but are relative to the window when the event is
/// forwarded to the controls
/**
* The coordinates are absolute when the event is sent to the
* GenericWindow, but are relative to the window when the event is
* forwarded to the controls
*/
int m_xPos, m_yPos;
};
......
......@@ -93,6 +93,12 @@ OSTooltip *MacOSXFactory::createOSTooltip()
}
OSPopup *MacOSXFactory::createOSPopup()
{
return new MacOSXPopup( getIntf() );
}
int MacOSXFactory::getScreenWidth() const
{
// TODO
......
......@@ -37,13 +37,13 @@ class MacOSXFactory: public OSFactory
/// Initialization method
virtual bool init();
/// Instantiate an object OSGraphics.
/// Instantiate an object OSGraphics
virtual OSGraphics *createOSGraphics( int width, int height );
/// Get the instance of the singleton OSLoop.
/// Get the instance of the singleton OSLoop
virtual OSLoop *getOSLoop();
/// Destroy the instance of OSLoop.
/// Destroy the instance of OSLoop
virtual void destroyOSLoop();
/// Instantiate an OSTimer with the given callback
......@@ -57,9 +57,12 @@ class MacOSXFactory: public OSFactory
bool dragDrop, bool playOnDrop,
OSWindow *pParent );
/// Instantiate an object OSTooltip.
/// Instantiate an object OSTooltip
virtual OSTooltip *createOSTooltip();
/// Instantiate an object OSPopup
virtual OSPopup *createOSPopup();
/// Get the directory separator
virtual const string &getDirSeparator() const { return m_dirSep; }
......
/*****************************************************************************
* macosx_popup.cpp
*****************************************************************************
* Copyright (C) 2003 the VideoLAN team
* $Id$
*
* Authors: Olivier Teulière <ipkiss@via.ecp.fr>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
#ifdef MACOSX_SKINS
#include "macosx_popup.hpp"
MacOSXPopup::MacOSXPopup( intf_thread_t *pIntf )
: OSPopup( pIntf )
{
// TODO
}
MacOSXPopup::~MacOSXPopup()
{
// TODO
}
void MacOSXPopup::show( int xPos, int yPos )
{
// TODO
}
void MacOSXPopup::hide()
{
// TODO
}
void MacOSXPopup::addItem( const string &rLabel, int pos )
{
// TODO
}
void MacOSXPopup::addSeparator( int pos )
{
// TODO
}
int MacOSXPopup::getPosFromId( int id ) const
{
// TODO
}
#endif
/*****************************************************************************
* macosx_popup.hpp
*****************************************************************************
* Copyright (C) 2003 the VideoLAN team
* $Id$
*
* Authors: Olivier Teulière <ipkiss@via.ecp.fr>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
#ifndef MACOSX_POPUP_HPP
#define MACOSX_POPUP_HPP
#include "../src/os_popup.hpp"
/// MacOSX implementation of OSPopup
class MacOSXPopup: public OSPopup
{
public:
MacOSXPopup( intf_thread_t *pIntf );
virtual ~MacOSXPopup();
/// Show the popup menu at the given (absolute) corrdinates
virtual void show( int xPos, int yPos );
/// Hide the popup menu
virtual void hide();
/// Append a new menu item with the given label to the popup menu
virtual void addItem( const string &rLabel, int pos );
/// Create a dummy menu item to separate sections
virtual void addSeparator( int pos );
/// Return the position of the item identified by the given id
virtual int getPosFromId( int id ) const;
};
#endif
......@@ -37,10 +37,10 @@ class MacOSXTooltip: public OSTooltip
virtual ~MacOSXTooltip();
// Show the tooltip
/// Show the tooltip
virtual void show( int left, int top, OSGraphics &rText );
// Hide the tooltip
/// Hide the tooltip
virtual void hide();
private:
......
......@@ -33,7 +33,10 @@
#include "../src/anchor.hpp"
#include "../src/bitmap_font.hpp"
#include "../src/ft2_font.hpp"
#include "../src/generic_layout.hpp"
#include "../src/popup.hpp"
#include "../src/theme.hpp"
#include "../commands/cmd_generic.hpp"
#include "../controls/ctrl_button.hpp"
#include "../controls/ctrl_checkbox.hpp"
#include "../controls/ctrl_image.hpp"
......@@ -45,6 +48,7 @@
#include "../controls/ctrl_text.hpp"
#include "../controls/ctrl_tree.hpp"
#include "../controls/ctrl_video.hpp"
#include "../utils/bezier.hpp"
#include "../utils/position.hpp"
#include "../utils/var_bool.hpp"
#include "../utils/var_text.hpp"
......@@ -95,6 +99,9 @@ Theme *Builder::build()
ADD_OBJECTS( BitmapFont );
ADD_OBJECTS( Font );
ADD_OBJECTS( Window );
// XXX: PopupMenus are created after the windows, so that the Win32Factory
// (at least) can give a valid window handle to the OSPopup objects
ADD_OBJECTS( PopupMenu );
ADD_OBJECTS( Layout );
ADD_OBJECTS( Anchor );
ADD_OBJECTS( Button );
......@@ -106,6 +113,10 @@ Theme *Builder::build()
ADD_OBJECTS( List );
ADD_OBJECTS( Tree );
ADD_OBJECTS( Video );
// MenuItems must be created after all the rest, so that the IDs of the
// other elements exist and can be parsed in the actions
ADD_OBJECTS( MenuItem );
ADD_OBJECTS( MenuSeparator );
return m_pTheme;
}
......@@ -258,6 +269,47 @@ void Builder::addFont( const BuilderData::Font &rData )
}
void Builder::addPopupMenu( const BuilderData::PopupMenu &rData )
{
Popup *pPopup = new Popup( getIntf(), m_pTheme->getWindowManager() );
m_pTheme->m_popups[rData.m_id] = PopupPtr( pPopup );
}
void Builder::addMenuItem( const BuilderData::MenuItem &rData )
{
Popup *pPopup = m_pTheme->getPopupById( rData.m_popupId );
if( pPopup == NULL )
{
msg_Err( getIntf(), "Unknown popup id: %s", rData.m_popupId.c_str() );
return;
}
CmdGeneric *pCommand = parseAction( rData.m_action );
if( pCommand == NULL )
{
msg_Err( getIntf(), "Invalid action: %s", rData.m_action.c_str() );
return;
}
pPopup->addItem( rData.m_label, *pCommand, rData.m_pos );
}
void Builder::addMenuSeparator( const BuilderData::MenuSeparator &rData )
{
Popup *pPopup = m_pTheme->getPopupById( rData.m_popupId );
if( pPopup == NULL )
{
msg_Err( getIntf(), "Unknown popup id: %s", rData.m_popupId.c_str() );
return;
}
pPopup->addSeparator( rData.m_pos );
}
void Builder::addWindow( const BuilderData::Window &rData )
{
TopWindow *pWin =
......@@ -272,7 +324,7 @@ void Builder::addWindow( const BuilderData::Window &rData )
void Builder::addLayout( const BuilderData::Layout &rData )
{
TopWindow *pWin = m_pTheme->getWindowById(rData.m_windowId);
TopWindow *pWin = m_pTheme->getWindowById( rData.m_windowId );
if( pWin == NULL )
{
msg_Err( getIntf(), "unknown window id: %s", rData.m_windowId.c_str() );
......@@ -298,7 +350,7 @@ void Builder::addLayout( const BuilderData::Layout &rData )
void Builder::addAnchor( const BuilderData::Anchor &rData )
{
GenericLayout *pLayout = m_pTheme->getLayoutById(rData.m_layoutId);
GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
if( pLayout == NULL )
{
msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
......@@ -333,7 +385,7 @@ void Builder::addButton( const BuilderData::Button &rData )
GenericBitmap *pBmpOver = pBmpUp;
GET_BMP( pBmpOver, rData.m_overId );
GenericLayout *pLayout = m_pTheme->getLayoutById(rData.m_layoutId);
GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
if( pLayout == NULL )
{
msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
......@@ -390,7 +442,7 @@ void Builder::addCheckbox( const BuilderData::Checkbox &rData )
GenericBitmap *pBmpOver2 = pBmpUp2;
GET_BMP( pBmpOver2, rData.m_over2Id );
GenericLayout *pLayout = m_pTheme->getLayoutById(rData.m_layoutId);
GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
if( pLayout == NULL )
{
msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
......@@ -449,14 +501,14 @@ void Builder::addImage( const BuilderData::Image &rData )
GenericBitmap *pBmp = NULL;
GET_BMP( pBmp, rData.m_bmpId );
GenericLayout *pLayout = m_pTheme->getLayoutById(rData.m_layoutId);
GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
if( pLayout == NULL )
{
msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
return;
}
TopWindow *pWindow = m_pTheme->getWindowById(rData.m_windowId);
TopWindow *pWindow = m_pTheme->getWindowById( rData.m_windowId );
if( pWindow == NULL )
{
msg_Err( getIntf(), "unknown window id: %s", rData.m_windowId.c_str() );
......@@ -526,7 +578,7 @@ void Builder::addImage( const BuilderData::Image &rData )
void Builder::addText( const BuilderData::Text &rData )
{
GenericLayout *pLayout = m_pTheme->getLayoutById(rData.m_layoutId);
GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
if( pLayout == NULL )
{
msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
......@@ -607,7 +659,7 @@ void Builder::addRadialSlider( const BuilderData::RadialSlider &rData )
GenericBitmap *pSeq = NULL;
GET_BMP( pSeq, rData.m_sequence );
GenericLayout *pLayout = m_pTheme->getLayoutById(rData.m_layoutId);
GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
if( pLayout == NULL )
{
msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
......@@ -661,7 +713,7 @@ void Builder::addSlider( const BuilderData::Slider &rData )
GET_BMP( pBgImage, rData.m_imageId );
}
GenericLayout *pLayout = m_pTheme->getLayoutById(rData.m_layoutId);
GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
if( pLayout == NULL )
{
msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
......@@ -737,7 +789,7 @@ void Builder::addList( const BuilderData::List &rData )
GenericBitmap *pBgBmp = NULL;
GET_BMP( pBgBmp, rData.m_bgImageId );
GenericLayout *pLayout = m_pTheme->getLayoutById(rData.m_layoutId);
GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
if( pLayout == NULL )
{
msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
......@@ -793,7 +845,7 @@ void Builder::addTree( const BuilderData::Tree &rData )
GET_BMP( pOpenBmp, rData.m_openImageId );
GET_BMP( pClosedBmp, rData.m_closedImageId );
GenericLayout *pLayout = m_pTheme->getLayoutById(rData.m_layoutId);
GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
if( pLayout == NULL )
{
msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
......@@ -840,7 +892,7 @@ void Builder::addTree( const BuilderData::Tree &rData )
void Builder::addVideo( const BuilderData::Video &rData )
{
GenericLayout *pLayout = m_pTheme->getLayoutById(rData.m_layoutId);
GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
if( pLayout == NULL )
{
msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
......
......@@ -26,20 +26,18 @@
#define BUILDER_HPP
#include "builder_data.hpp"
#include "../src/os_graphics.hpp"
#include "../src/generic_window.hpp"
#include "../src/generic_layout.hpp"
#include "../src/generic_bitmap.hpp"
#include "../src/generic_font.hpp"
#include "../commands/cmd_generic.hpp"
#include "../controls/ctrl_generic.hpp"
#include "../utils/bezier.hpp"
#include "../src/skin_common.hpp"
#include <string>
#include <list>
#include <map>
class Theme;
class Bezier;
class CmdGeneric;
class GenericFont;
class Position;
class Box;
/// Class for skin construction
......@@ -71,6 +69,9 @@ class Builder: public SkinObject
void addSubBitmap( const BuilderData::SubBitmap &rData );
void addBitmapFont( const BuilderData::BitmapFont &rData );
void addFont( const BuilderData::Font &rData );
void addPopupMenu( const BuilderData::PopupMenu &rData );
void addMenuItem( const BuilderData::MenuItem &rData );
void addMenuSeparator( const BuilderData::MenuSeparator &rData );
void addWindow( const BuilderData::Window &rData );
void addLayout( const BuilderData::Layout &rData );
void addAnchor( const BuilderData::Anchor &rData );
......@@ -84,7 +85,7 @@ class Builder: public SkinObject
void addTree( const BuilderData::Tree &rData );
void addVideo( const BuilderData::Video &rData );
/// Compute the position of a control
/// Compute the position of a control
const Position makePosition( const string &rLeftTop,
const string &rRightBottom,
int xPos, int yPos, int width, int height,
......
......@@ -3,6 +3,9 @@ Bitmap id:string fileName:string alphaColor:uint32_t nbFrames:int fps:int
SubBitmap id:string parent:string x:int y:int width:int height:int nbFrames:int fps:int
BitmapFont id:string file:string type:string
Font id:string fontFile:string size:int
PopupMenu id:string
MenuItem label:string action:string pos:int popupId:string
MenuSeparator pos:int popupId:string
Window id:string xPos:int yPos:int visible:bool dragDrop:bool playOnDrop:bool
Layout id:string width:int height:int minWidth:int maxWidth:int minHeight:int maxHeight:int windowId:string
Anchor xPos:int yPos:int range:int priority:int points:string layoutId:string
......
......@@ -112,6 +112,43 @@ m_id( id ), m_fontFile( fontFile ), m_size( size ) {}
/// List
list<Font> m_listFont;
/// Type definition
struct PopupMenu
{
PopupMenu( const string & id ):
m_id( id ) {}
string m_id;
};
/// List
list<PopupMenu> m_listPopupMenu;
/// Type definition
struct MenuItem
{
MenuItem( const string & label, const string & action, int pos, const string & popupId ):
m_label( label ), m_action( action ), m_pos( pos ), m_popupId( popupId ) {}
string m_label;
string m_action;
int m_pos;
string m_popupId;
};
/// List
list<MenuItem> m_listMenuItem;
/// Type definition
struct MenuSeparator
{
MenuSeparator( int pos, const string & popupId ):
m_pos( pos ), m_popupId( popupId ) {}
int m_pos;
string m_popupId;
};
/// List
list<MenuSeparator> m_listMenuSeparator;
/// Type definition
struct Window
{
......
......@@ -216,7 +216,17 @@ CmdGeneric *Interpreter::parseAction( const string &rAction, Theme *pTheme )
}
else
{
msg_Err( getIntf(), "Unknown window (%s)", windowId.c_str() );
// It was maybe the id of a popup
Popup *pPopup = pTheme->getPopupById( windowId );
if( pPopup )
{
pCommand = new CmdShowPopup( getIntf(), *pPopup );
}
else
{
msg_Err( getIntf(), "Unknown window or popup (%s)",
windowId.c_str() );
}
}
}
else if( rAction.find( ".hide()" ) != string::npos )
......
......@@ -129,6 +129,36 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr )
m_pData->m_listBitmapFont.push_back( font );
}
else if( rName == "PopupMenu" )
{
RequireDefault( "id" );
m_popupPosList.push_back(0);
m_curPopupId = uniqueId( attr["id"] );
const BuilderData::PopupMenu popup( m_curPopupId );
m_pData->m_listPopupMenu.push_back( popup );
}
else if( rName == "MenuItem" )
{
RequireDefault( "label" );
CheckDefault( "action", "none" );
const BuilderData::MenuItem item( attr["label"], attr["action"],
m_popupPosList.back(),
m_curPopupId );
m_pData->m_listMenuItem.push_back( item );
m_popupPosList.back()++;
}
else if( rName == "MenuSeparator" )
{
const BuilderData::MenuSeparator sep( m_popupPosList.back(),
m_curPopupId );
m_pData->m_listMenuSeparator.push_back( sep );
m_popupPosList.back()++;
}
else if( rName == "Button" )
{
RequireDefault( "up" );
......@@ -530,6 +560,11 @@ void SkinParser::handleEndElement( const string &rName )
{
m_curTreeId = "";
}
else if( rName == "Popup" )
{
m_curPopupId = "";
m_popupPosList.pop_back();
}
}
......
......@@ -51,8 +51,11 @@ class SkinParser: public XMLParser
string m_curBitmapId;
string m_curWindowId;
string m_curLayoutId;
string m_curPopupId;
string m_curListId;
string m_curTreeId;
/// Current position of menu items in the popups
list<int> m_popupPosList;
/// Current offset of the controls
int m_xOffset, m_yOffset;
list<int> m_xOffsetList, m_yOffsetList;
......