haikuwebkit/Source/WebCore/platform/haiku/PopupMenuHaiku.cpp

193 lines
5.4 KiB
C++

/*
* This file is part of the popup menu implementation for <select> elements in WebCore.
*
* Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "config.h"
#include "PopupMenuHaiku.h"
#include "FrameView.h"
#include "NotImplemented.h"
#include <Application.h>
#include <Handler.h>
#include <MenuItem.h>
#include <Message.h>
#include <PopUpMenu.h>
#include <String.h>
#include <Window.h>
#include <support/Locker.h>
#include <support/Autolock.h>
namespace WebCore {
static const uint32 kPopupResult = 'pmrs';
static const uint32 kPopupHidden = 'pmhd';
// This BHandler is added to the application (main) thread, so that we
// invoke methods on the PopupMenuClient within the main thread.
class PopupMenuHandler : public BHandler {
public:
PopupMenuHandler(PopupMenuClient* popupClient)
: m_popupClient(popupClient)
{
}
virtual void MessageReceived(BMessage* message)
{
switch (message->what) {
case kPopupResult: {
int32 index = 0;
message->FindInt32("index", &index);
m_popupClient->valueChanged(index);
break;
}
case kPopupHidden:
m_popupClient->popupDidHide();
break;
default:
BHandler::MessageReceived(message);
}
}
private:
PopupMenuClient* m_popupClient;
};
class HaikuPopup : public BPopUpMenu {
public:
HaikuPopup(PopupMenuClient* popupClient)
: BPopUpMenu("WebCore Popup", true, false)
, m_popupClient(popupClient)
, m_Handler(popupClient)
{
if (be_app->Lock()) {
be_app->AddHandler(&m_Handler);
be_app->Unlock();
}
SetAsyncAutoDestruct(false);
}
virtual ~HaikuPopup()
{
if (be_app->Lock()) {
be_app->RemoveHandler(&m_Handler);
be_app->Unlock();
}
}
void show(const IntRect& rect, FrameView* view, int index)
{
// Clean out the menu first
for (int32 i = CountItems() - 1; i >= 0; i--)
delete RemoveItem(i);
// Popuplate the menu from the client
int itemCount = m_popupClient->listSize();
for (int i = 0; i < itemCount; i++) {
if (m_popupClient->itemIsSeparator(i))
AddSeparatorItem();
else {
// NOTE: WebCore distinguishes between "Group" and "Label"
// here, but both types of item (radio or check mark) currently
// look the same on Haiku.
BString label(m_popupClient->itemText(i));
BMessage* message = new BMessage(kPopupResult);
message->AddInt32("index", i);
BMenuItem* item = new BMenuItem(label.String(), message);
AddItem(item);
item->SetTarget(BMessenger(&m_Handler));
item->SetEnabled(m_popupClient->itemIsEnabled(i));
item->SetMarked(i == index);
}
}
// We need to force a layout now, or the item frames will not be
// computed yet, so we cannot move the current item under the mouse.
DoLayout();
// Account for frame of menu field
BRect screenRect(view->contentsToScreen(rect));
screenRect.OffsetBy(2, 2);
// Move currently selected item under the mouse.
if (BMenuItem* item = ItemAt(index))
screenRect.OffsetBy(0, -item->Frame().top);
BRect openRect = Bounds().OffsetToSelf(screenRect.LeftTop());
Go(screenRect.LeftTop(), true, true, openRect, true);
}
void hide()
{
if (!IsHidden())
Hide();
}
private:
virtual void Hide()
{
BPopUpMenu::Hide();
be_app->PostMessage(kPopupHidden, &m_Handler);
}
PopupMenuClient* m_popupClient;
PopupMenuHandler m_Handler;
};
PopupMenuHaiku::PopupMenuHaiku(PopupMenuClient* client)
: m_popupClient(client)
, m_menu(new HaikuPopup(client))
{
// We don't need additional references to the client, since we completely
// control any sub-objects we create that need it as well.
}
PopupMenuHaiku::~PopupMenuHaiku()
{
delete m_menu;
}
void PopupMenuHaiku::disconnectClient()
{
m_popupClient = 0;
}
void PopupMenuHaiku::show(const IntRect& rect, FrameView* view, int index)
{
// The menu will update itself from the PopupMenuClient before showing.
m_menu->show(rect, view, index);
}
void PopupMenuHaiku::hide()
{
m_menu->hide();
}
void PopupMenuHaiku::updateFromElement()
{
client()->setTextFromItem(m_popupClient->selectedIndex());
}
} // namespace WebCore