1/* 2 * Copyright (C) 2007 Holger Hans Peter Freyther zecke@selfish.org 3 * (C) 2009 Kenneth Rohde Christiansen 4 * (C) 2009 INdT, Instituto Nokia de Technologia 5 * (C) 2009-2010 ProFUSION embedded systems 6 * (C) 2009-2010 Samsung Electronics 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 */ 22 23#include "config.h" 24#include "ScrollbarEfl.h" 25 26#include "Frame.h" 27#include "FrameView.h" 28#include "GraphicsContext.h" 29#include "HostWindow.h" 30#include "IntRect.h" 31#include "Page.h" 32#include "RenderThemeEfl.h" 33#include "ScrollbarTheme.h" 34#include "Settings.h" 35 36#include <Ecore.h> 37#include <Edje.h> 38#include <Evas.h> 39#include <new> 40#include <string> 41#include <wtf/OwnArrayPtr.h> 42#include <wtf/text/CString.h> 43 44using namespace std; 45using namespace WebCore; 46 47PassRefPtr<Scrollbar> Scrollbar::createNativeScrollbar(ScrollableArea* scrollableArea, ScrollbarOrientation orientation, ScrollbarControlSize size) 48{ 49 if (Settings::mockScrollbarsEnabled()) 50 return adoptRef(new Scrollbar(scrollableArea, orientation, size)); 51 52 return adoptRef(new ScrollbarEfl(scrollableArea, orientation, size)); 53} 54 55ScrollbarEfl::ScrollbarEfl(ScrollableArea* scrollableArea, ScrollbarOrientation orientation, ScrollbarControlSize controlSize) 56 : Scrollbar(scrollableArea, orientation, controlSize) 57 , m_lastPos(0) 58 , m_lastTotalSize(0) 59 , m_lastVisibleSize(0) 60{ 61} 62 63ScrollbarEfl::~ScrollbarEfl() 64{ 65 if (!evasObject()) 66 return; 67 68 evas_object_del(evasObject()); 69 setEvasObject(0); 70} 71 72static void scrollbarEflEdjeMessage(void* data, Evas_Object*, Edje_Message_Type messageType, int id, void* message) 73{ 74 if (!id) { 75 EINA_LOG_ERR("Unknown message id '%d' from scroll bar theme.", id); 76 return; 77 } 78 79 if (messageType != EDJE_MESSAGE_FLOAT) { 80 EINA_LOG_ERR("Message id '%d' of incorrect type from scroll bar theme. " 81 "Expected '%d', got '%d'.", 82 id, EDJE_MESSAGE_FLOAT, messageType); 83 return; 84 } 85 86 ScrollbarEfl* that = static_cast<ScrollbarEfl*>(data); 87 88 Edje_Message_Float* messageFloat = static_cast<Edje_Message_Float*>(message); 89 int value = messageFloat->val * (that->totalSize() - that->visibleSize()); 90 that->scrollableArea()->scrollToOffsetWithoutAnimation(that->orientation(), value); 91} 92 93void ScrollbarEfl::show() 94{ 95 if (Evas_Object* object = evasObject()) 96 evas_object_show(object); 97} 98 99void ScrollbarEfl::hide() 100{ 101 if (Evas_Object* object = evasObject()) 102 evas_object_hide(object); 103} 104 105void ScrollbarEfl::setParent(ScrollView* view) 106{ 107 Widget::setParent(view); 108 109 if (!view || !view->evasObject()) 110 return; 111 112 Frame* frame = toFrameView(view)->frame(); 113 if (!frame || !frame->page()) 114 return; 115 116 String theme = static_cast<RenderThemeEfl*>(frame->page()->theme())->themePath(); 117 118 const char* group = (orientation() == HorizontalScrollbar) ? "scrollbar.horizontal" : "scrollbar.vertical"; 119 if (theme.isEmpty()) { 120 EINA_LOG_ERR("Could not load theme '%s': no theme path set.", group); 121 return; 122 } 123 124 if (!evasObject()) { 125 setEvasObject(edje_object_add(evas_object_evas_get(view->evasObject()))); 126 if (!evasObject()) { 127 EINA_LOG_ERR("Could not create edje object for view=%p", view); 128 return; 129 } 130 frameRectsChanged(); 131 edje_object_message_handler_set(evasObject(), scrollbarEflEdjeMessage, this); 132 } 133 134 if (!edje_object_file_set(evasObject(), theme.utf8().data(), group)) { 135 Edje_Load_Error err = edje_object_load_error_get(evasObject()); 136 const char* errmessage = edje_load_error_str(err); 137 EINA_LOG_ERR("Could not load theme '%s' from file '%s': #%d '%s'", 138 group, theme.utf8().data(), err, errmessage); 139 return; 140 } 141 142 evas_object_smart_member_add(evasObject(), view->evasObject()); 143 evas_object_show(evasObject()); 144} 145 146void ScrollbarEfl::updateThumbPosition() 147{ 148 updateThumbPositionAndProportion(); 149} 150 151void ScrollbarEfl::updateThumbProportion() 152{ 153 updateThumbPositionAndProportion(); 154} 155 156void ScrollbarEfl::updateThumbPositionAndProportion() 157{ 158 if (!evasObject()) 159 return; 160 161 int pos = currentPos(); 162 int tSize = totalSize(); 163 int vSize = visibleSize(); 164 165 if (m_lastPos == pos 166 && m_lastTotalSize == tSize 167 && m_lastVisibleSize == vSize) 168 return; 169 170 m_lastPos = pos; 171 m_lastTotalSize = tSize; 172 m_lastVisibleSize = vSize; 173 174 OwnArrayPtr<char> buffer = adoptArrayPtr(new char[sizeof(Edje_Message_Float_Set) + sizeof(double)]); 175 Edje_Message_Float_Set* message = new(buffer.get()) Edje_Message_Float_Set; 176 message->count = 2; 177 178 if (tSize - vSize > 0) 179 message->val[0] = pos / static_cast<float>(tSize - vSize); 180 else 181 message->val[0] = 0.0; 182 183 if (tSize > 0) 184 message->val[1] = vSize / static_cast<float>(tSize); 185 else 186 message->val[1] = 0.0; 187 188 edje_object_message_send(evasObject(), EDJE_MESSAGE_FLOAT_SET, 0, message); 189} 190 191void ScrollbarEfl::setFrameRect(const IntRect& rect) 192{ 193 Widget::setFrameRect(rect); 194 frameRectsChanged(); 195} 196 197void ScrollbarEfl::frameRectsChanged() 198{ 199 Evas_Object* object = evasObject(); 200 Evas_Coord x, y; 201 202 if (!parent() || !object) 203 return; 204 205 IntRect rect = frameRect(); 206 if (parent()->isScrollViewScrollbar(this)) 207 rect.setLocation(parent()->convertToContainingWindow(rect.location())); 208 else 209 rect.setLocation(parent()->contentsToWindow(rect.location())); 210 211 evas_object_geometry_get(root()->evasObject(), &x, &y, 0, 0); 212 evas_object_move(object, x + rect.x(), y + rect.y()); 213 evas_object_resize(object, rect.width(), rect.height()); 214} 215