"Fossies" - the Fresh Open Source Software Archive

Member "google-gadgets-for-linux-0.11.2/ggadget/sidebar.cc" (28 Dec 2009, 26980 Bytes) of package /linux/misc/old/google-gadgets-for-linux-0.11.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2   Copyright 2008 Google Inc.
    3 
    4   Licensed under the Apache License, Version 2.0 (the "License");
    5   you may not use this file except in compliance with the License.
    6   You may obtain a copy of the License at
    7 
    8        http://www.apache.org/licenses/LICENSE-2.0
    9 
   10   Unless required by applicable law or agreed to in writing, software
   11   distributed under the License is distributed on an "AS IS" BASIS,
   12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13   See the License for the specific language governing permissions and
   14   limitations under the License.
   15 */
   16 
   17 #include <vector>
   18 #include <list>
   19 
   20 #include "sidebar.h"
   21 
   22 #include "button_element.h"
   23 #include "canvas_interface.h"
   24 #include "div_element.h"
   25 #include "element_factory.h"
   26 #include "elements.h"
   27 #include "gadget_consts.h"
   28 #include "gadget.h"
   29 #include "file_manager_factory.h"
   30 #include "host_interface.h"
   31 #include "img_element.h"
   32 #include "math_utils.h"
   33 #include "scriptable_binary_data.h"
   34 #include "view_element.h"
   35 #include "view.h"
   36 #include "messages.h"
   37 #include "small_object.h"
   38 
   39 namespace ggadget {
   40 
   41 static const double kGadgetSpacing = 1;
   42 static const double kUndockDragThreshold = 2;
   43 static const double kBackgroundOpacity = 0.618;
   44 static const double kSideBarMinWidth = 50;
   45 static const double kSideBarMaxWidth = 999;
   46 static const double kBorderWidth = 3;
   47 
   48 class SideBar::Impl : public View {
   49  public:
   50   class SideBarViewHost : public ViewHostInterface, public SmallObject<> {
   51    public:
   52     SideBarViewHost(SideBar::Impl *owner, size_t index)
   53       : owner_(owner),
   54         view_element_(new ViewElement(owner, NULL, true)),
   55         initial_index_(index) {
   56       view_element_->SetVisible(false);
   57       owner_->InsertViewElement(index, view_element_);
   58     }
   59     virtual ~SideBarViewHost() {
   60       owner_->RemoveViewElement(view_element_);
   61       owner_->LayoutSubViews();
   62       view_element_ = NULL;
   63       DLOG("SideBarViewHost Dtor: %p", this);
   64     }
   65     virtual ViewHostInterface::Type GetType() const {
   66       return ViewHostInterface::VIEW_HOST_MAIN;
   67     }
   68     virtual void Destroy() { delete this; }
   69     virtual void SetView(ViewInterface *view) {
   70       // set invisible before ShowView is called
   71       view_element_->SetVisible(false);
   72       view_element_->SetChildView(down_cast<View*>(view));
   73     }
   74     virtual ViewInterface *GetView() const {
   75       return view_element_->GetChildView();
   76     }
   77     virtual GraphicsInterface *NewGraphics() const {
   78       return owner_->view_host_->NewGraphics();
   79     }
   80     virtual void *GetNativeWidget() const {
   81       return owner_->GetNativeWidget();
   82     }
   83     virtual void ViewCoordToNativeWidgetCoord(double x, double y,
   84                                               double *wx, double *wy) const {
   85       view_element_->ChildViewCoordToViewCoord(x, y, &x, &y);
   86       owner_->view_host_->ViewCoordToNativeWidgetCoord(x, y, wx, wy);
   87     }
   88     virtual void NativeWidgetCoordToViewCoord(double x, double y,
   89                                               double *vx, double *vy) const {
   90       owner_->view_host_->NativeWidgetCoordToViewCoord(x, y, &x, &y);
   91       view_element_->ViewCoordToChildViewCoord(x, y, vx, vy);
   92     }
   93     virtual void QueueDraw() {
   94       if (view_element_)
   95         view_element_->QueueDrawChildView();
   96     }
   97     virtual void QueueResize() {
   98       owner_->LayoutSubViews();
   99     }
  100     virtual void EnableInputShapeMask(bool /* enable */) {
  101       // Do nothing.
  102     }
  103     virtual void SetResizable(ViewInterface::ResizableMode) {}
  104     virtual void SetCaption(const std::string &) {}
  105     virtual void SetShowCaptionAlways(bool) {}
  106     virtual void SetCursor(ViewInterface::CursorType type) {
  107       view_element_->SetCursor(type);
  108       owner_->view_host_->SetCursor(type);
  109     }
  110     virtual void ShowTooltip(const std::string &tooltip) {
  111       view_element_->SetTooltip(tooltip);
  112       owner_->ShowElementTooltip(view_element_);
  113     }
  114     virtual void ShowTooltipAtPosition(const std::string &tooltip,
  115                                        double x, double y) {
  116       view_element_->SetTooltip(tooltip);
  117       double scale = view_element_->GetScale();
  118       owner_->ShowElementTooltipAtPosition(view_element_, x * scale, y * scale);
  119     }
  120     virtual bool ShowView(bool modal, int flags,
  121                           Slot1<bool, int> *feedback_handler) {
  122       GGL_UNUSED(modal);
  123       GGL_UNUSED(flags);
  124       delete feedback_handler;
  125       if (view_element_->GetChildView()) {
  126         view_element_->SetVisible(true);
  127         owner_->LayoutSubViews();
  128         return true;
  129       }
  130       return false;
  131     }
  132     virtual void CloseView() {
  133       view_element_->SetVisible(false);
  134       owner_->LayoutSubViews();
  135     }
  136     virtual bool ShowContextMenu(int button) {
  137       return owner_->view_host_->ShowContextMenu(button);
  138     }
  139     virtual void BeginResizeDrag(int button, ViewInterface::HitTest hittest) {
  140       GGL_UNUSED(button);
  141       GGL_UNUSED(hittest);
  142     }
  143     virtual void BeginMoveDrag(int button) {
  144       GGL_UNUSED(button);
  145     }
  146     virtual void Alert(const ViewInterface *view, const char *message) {
  147       owner_->view_host_->Alert(view, message);
  148     }
  149     virtual ConfirmResponse Confirm(const ViewInterface *view,
  150                                     const char *message, bool cancel_button) {
  151       return owner_->view_host_->Confirm(view, message, cancel_button);
  152     }
  153     virtual std::string Prompt(const ViewInterface *view,
  154                                const char *message,
  155                                const char *default_value) {
  156       return owner_->view_host_->Prompt(view, message, default_value);
  157     }
  158     virtual int GetDebugMode() const {
  159       return owner_->view_host_->GetDebugMode();
  160     }
  161     size_t GetInitialIndex() const { return initial_index_; }
  162    private:
  163     SideBar::Impl *owner_;
  164     ViewElement *view_element_;
  165     size_t initial_index_;
  166   };
  167 
  168   Impl(SideBar *owner, ViewHostInterface *view_host)
  169     : View(view_host, NULL, NULL, NULL),
  170       owner_(owner),
  171       view_host_(view_host),
  172       null_element_(NULL),
  173       blank_height_(0),
  174       mouse_move_event_x_(-1),
  175       mouse_move_event_y_(-1),
  176       hit_element_bottom_(false),
  177       hit_element_normal_part_(false),
  178       hit_sidebar_border_(false),
  179       hittest_(HT_CLIENT),
  180       original_width_(0),
  181       original_height_(0),
  182       top_div_(NULL),
  183       main_div_(NULL),
  184       google_icon_(NULL),
  185       add_gadget_button_(NULL),
  186       menu_button_(NULL),
  187       close_button_(NULL),
  188       children_(NULL),
  189       initializing_(false) {
  190     SetResizable(ViewInterface::RESIZABLE_TRUE);
  191     EnableCanvasCache(false);
  192     SetupUI();
  193   }
  194   ~Impl() {
  195   }
  196 
  197  public:
  198   virtual EventResult OnMouseEvent(const MouseEvent &event) {
  199     hittest_ = HT_CLIENT;
  200 
  201     EventResult result = EVENT_RESULT_UNHANDLED;
  202     // don't sent mouse event to view elements when layouting or resizing
  203     if (!hit_element_bottom_)
  204       result = View::OnMouseEvent(event);
  205 
  206     if (event.GetType() == Event::EVENT_MOUSE_DOWN) {
  207       ViewElement *e = GetMouseOverViewElement();
  208       onclick_signal_(e ? e->GetChildView() : NULL);
  209     }
  210 
  211     if (result == EVENT_RESULT_UNHANDLED && !IsMinimized()) {
  212       if (event.GetX() >= 0 && event.GetX() < kBorderWidth) {
  213         hittest_ = HT_LEFT;
  214         SetCursor(CURSOR_SIZEWE);
  215       } else if (event.GetX() < GetWidth() &&
  216                event.GetX() >= GetWidth() - kBorderWidth) {
  217         hittest_ = HT_RIGHT;
  218         SetCursor(CURSOR_SIZEWE);
  219       }
  220     }
  221 
  222     if (event.GetButton() != MouseEvent::BUTTON_LEFT)
  223       return result;
  224 
  225     size_t index = 0;
  226     double x, y;
  227     BasicElement *element = NULL;
  228     ViewElement *focused = GetMouseOverViewElement();
  229     double offset = mouse_move_event_y_ - event.GetY();
  230     switch (event.GetType()) {
  231       case Event::EVENT_MOUSE_DOWN:
  232         DLOG("Mouse down at (%f,%f)", event.GetX(), event.GetY());
  233         mouse_move_event_x_ = event.GetX();
  234         mouse_move_event_y_ = event.GetY();
  235 
  236         if (hittest_ != HT_CLIENT) {
  237           hit_sidebar_border_ = true;
  238           return result;
  239         }
  240 
  241         if (!focused) return result;
  242         focused->ViewCoordToSelfCoord(event.GetX(), event.GetY(), &x, &y);
  243         switch (focused->GetHitTest(x, y)) {
  244           case HT_BOTTOM:
  245             hit_element_bottom_ = true;
  246             // record the original height of each view elements
  247             for (; index < children_->GetCount(); ++index) {
  248               element = children_->GetItemByIndex(index);
  249               elements_height_.push_back(element->GetPixelHeight());
  250             }
  251             if (element) {
  252               blank_height_ = main_div_->GetPixelHeight() -
  253                   element->GetPixelY() - element->GetPixelHeight();
  254             }
  255             break;
  256           case HT_CLIENT:
  257             hit_element_normal_part_ = true;
  258             break;
  259           default:
  260             break;
  261         }
  262         return result;
  263         break;
  264       case Event::EVENT_MOUSE_UP:
  265         ResetState();
  266         return result;
  267         break;
  268       case Event::EVENT_MOUSE_MOVE:  // handle it soon
  269         if ((mouse_move_event_x_ < 0 && mouse_move_event_y_ < 0) ||
  270             result != EVENT_RESULT_UNHANDLED)
  271           return result;
  272         if (!focused) {
  273           // if mouse over null_element_, BasicElement::GetMouseOverElement()
  274           // will not return it. Check it specially
  275           if (null_element_) {
  276             double x, y;
  277             null_element_->ViewCoordToSelfCoord(event.GetX(), event.GetY(),
  278                                                 &x, &y);
  279             if (y >= 0 && y <= null_element_->GetPixelHeight()) {
  280               return EVENT_RESULT_HANDLED;
  281             }
  282           }
  283           return result;
  284         }
  285         if (hit_element_bottom_) {
  286           // set cursor so that user understand that it's still in layout process
  287           SetCursor(CURSOR_SIZENS);
  288           size_t index = focused->GetIndex();
  289           if (offset < 0) {
  290             if (DownResize(false, index + 1, &offset) &&
  291                 UpResize(true, index, &offset)) {
  292               DownResize(true, index + 1, &offset);
  293               QueueDraw();
  294             }
  295           } else {
  296             UpResize(true, index, &offset);
  297             LayoutSubViews();
  298           }
  299         } else if (hit_element_normal_part_ && focused->GetChildView() &&
  300                    (std::abs(offset) > kUndockDragThreshold ||
  301                     std::abs(event.GetX() - mouse_move_event_x_) >
  302                     kUndockDragThreshold)) {
  303           focused->ViewCoordToChildViewCoord(mouse_move_event_x_,
  304                                              mouse_move_event_y_, &x, &y);
  305           onundock_signal_(focused->GetChildView(), focused->GetIndex(), x, y);
  306           ResetState();
  307         } else if (hit_sidebar_border_) {
  308           return EVENT_RESULT_UNHANDLED;
  309         }
  310         break;
  311       default:
  312         return result;
  313     }
  314 
  315     return EVENT_RESULT_HANDLED;
  316   }
  317 
  318   virtual HitTest GetHitTest() const {
  319     // Always return HT_CLIENT except when mouse cursor is on left or right
  320     // border.
  321     return hittest_;
  322   }
  323 
  324   virtual bool OnAddContextMenuItems(MenuInterface *menu) {
  325     BasicElement *e = GetMouseOverElement();
  326     if (e && e->IsInstanceOf(ViewElement::CLASS_ID)) {
  327       e->OnAddContextMenuItems(menu);
  328     } else {
  329       onmenu_signal_(menu);
  330     }
  331     // In sidebar mode, view host shouldn't add any host level menu items.
  332     return false;
  333   }
  334 
  335   virtual bool OnSizing(double *width, double *height) {
  336     return kSideBarMinWidth < *width && *width < kSideBarMaxWidth &&
  337            *height >= main_div_->GetPixelY();
  338   }
  339 
  340   virtual void SetSize(double width, double height) {
  341     if (top_div_->IsVisible() && main_div_->IsVisible()) {
  342       // Not minimized.
  343       View::SetSize(width, height);
  344       original_width_ = width;
  345       original_height_ = height;
  346     } else if (top_div_->IsVisible()) {
  347       // horizontal minimized.
  348       View::SetSize(width, main_div_->GetPixelY());
  349       original_width_ = width;
  350     } else {
  351       // vertical minimized.
  352       View::SetSize(kBorderWidth, height);
  353       original_height_ = height;
  354     }
  355 
  356     if (main_div_->IsVisible()) {
  357       main_div_->SetPixelWidth(width - kBorderWidth * 2);
  358       main_div_->SetPixelHeight(height - kBorderWidth - main_div_->GetPixelY());
  359     }
  360     if (top_div_->IsVisible()) {
  361       top_div_->SetPixelWidth(width - kBorderWidth * 2);
  362     }
  363     LayoutSubViews();
  364   }
  365 
  366  public:
  367   ViewElement *GetMouseOverViewElement() {
  368     BasicElement *e = GetMouseOverElement();
  369     return (e && e->IsInstanceOf(ViewElement::CLASS_ID)) ?
  370            down_cast<ViewElement*>(e) : NULL;
  371   }
  372 
  373   ViewHostInterface *NewViewHost(size_t index) {
  374     DLOG("sidebar: NewViewHost with index: %zu", index);
  375     SideBarViewHost *vh = new SideBarViewHost(this, index);
  376     return vh;
  377   }
  378 
  379   void Minimize(bool vertical) {
  380     // Don't minimize again if it's already minimized.
  381     if (!IsMinimized()) {
  382       if (vertical) {
  383         top_div_->SetVisible(false);
  384         main_div_->SetVisible(false);
  385       } else {
  386         main_div_->SetVisible(false);
  387       }
  388       SetSize(original_width_, original_height_);
  389     }
  390   }
  391 
  392   bool IsMinimized() const {
  393     return !(top_div_->IsVisible() && main_div_->IsVisible());
  394   }
  395 
  396   void Restore() {
  397     if (IsMinimized()) {
  398       top_div_->SetVisible(true);
  399       main_div_->SetVisible(true);
  400       SetSize(original_width_, original_height_);
  401     }
  402   }
  403 
  404   size_t GetIndexOfPosition(double y) const {
  405     size_t count = children_->GetCount();
  406     for (size_t i = 0; i < count; ++i) {
  407       ViewElement *e = down_cast<ViewElement*>(children_->GetItemByIndex(i));
  408       double x, middle;
  409       e->SelfCoordToViewCoord(0, e->GetPixelHeight()/2, &x, &middle);
  410       if (y < middle)
  411         return i;
  412     }
  413     return count;
  414   }
  415 
  416   size_t GetIndexOfView(const ViewInterface *view) const {
  417     size_t count = children_->GetCount();
  418     for (size_t i = 0; i < count; ++i) {
  419       ViewElement *e = down_cast<ViewElement*>(children_->GetItemByIndex(i));
  420       View *v = e->GetChildView();
  421       if (v == view)
  422         return i;
  423     }
  424     return kInvalidIndex;
  425   }
  426 
  427   void InsertPlaceholder(size_t index, double height) {
  428     // only one null element is allowed
  429     if (!null_element_) {
  430       null_element_ = new ViewElement(this, NULL, true);
  431     }
  432     null_element_->SetPixelHeight(height);
  433     InsertViewElement(index, null_element_);
  434   }
  435 
  436   void ClearPlaceholder() {
  437     if (null_element_) {
  438       RemoveViewElement(null_element_);
  439       null_element_ = NULL;
  440       LayoutSubViews();
  441     }
  442   }
  443 
  444   void EnumerateViews(Slot2<bool, size_t, View*> *slot) {
  445     ASSERT(slot);
  446     size_t count = children_->GetCount();
  447     for (size_t i = 0; i < count; ++i) {
  448       ViewElement *e = down_cast<ViewElement*>(children_->GetItemByIndex(i));
  449       View *v = e->GetChildView();
  450       if (v && !(*slot)(i, v))
  451         break;
  452     }
  453     delete slot;
  454   }
  455 
  456   void ResetState() {
  457     mouse_move_event_x_ = -1;
  458     mouse_move_event_y_ = -1;
  459     hit_element_bottom_ = false;
  460     hit_element_normal_part_ = false;
  461     hit_sidebar_border_ = false;
  462     blank_height_ = 0;
  463     elements_height_.clear();
  464   }
  465 
  466   void SetupUI() {
  467     ImgElement *background = new ImgElement(this, NULL);
  468     GetChildren()->InsertElement(background, NULL);
  469     background->SetSrc(Variant(kVDMainBackground));
  470     background->SetStretchMiddle(true);
  471     background->SetOpacity(kBackgroundOpacity);
  472     background->SetPixelX(0);
  473     background->SetPixelY(0);
  474     background->SetRelativeWidth(1);
  475     background->SetRelativeHeight(1);
  476     background->EnableCanvasCache(true);
  477 
  478     top_div_ = new DivElement(this, NULL);
  479     GetChildren()->InsertElement(top_div_, NULL);
  480     top_div_->SetPixelX(kBorderWidth);
  481     top_div_->SetPixelY(kBorderWidth);
  482 
  483     google_icon_ = new ImgElement(this, NULL);
  484     top_div_->GetChildren()->InsertElement(google_icon_, NULL);
  485     google_icon_->SetSrc(Variant(kSideBarGoogleIcon));
  486     google_icon_->SetPixelX(0);
  487     google_icon_->SetPixelY(0);
  488     google_icon_->SetEnabled(true);
  489     google_icon_->SetCursor(CURSOR_HAND);
  490 
  491     DivElement *button_div = new DivElement(this, NULL);
  492     top_div_->GetChildren()->InsertElement(button_div, NULL);
  493     button_div->SetRelativePinX(1);
  494     button_div->SetRelativeX(1);
  495     button_div->SetPixelY(0);
  496     button_div->SetRelativeHeight(1);
  497 
  498     add_gadget_button_ = new ButtonElement(this, NULL);
  499     button_div->GetChildren()->InsertElement(add_gadget_button_, NULL);
  500     add_gadget_button_->SetImage(Variant(kSBButtonAddUp));
  501     add_gadget_button_->SetDownImage(Variant(kSBButtonAddDown));
  502     add_gadget_button_->SetOverImage(Variant(kSBButtonAddOver));
  503     add_gadget_button_->SetTooltip(GM_("SIDEBAR_ADD_GADGETS_TOOLTIP"));
  504 
  505     menu_button_ = new ButtonElement(this, NULL);
  506     button_div->GetChildren()->InsertElement(menu_button_, NULL);
  507     menu_button_->SetImage(Variant(kSBButtonMenuUp));
  508     menu_button_->SetDownImage(Variant(kSBButtonMenuDown));
  509     menu_button_->SetOverImage(Variant(kSBButtonMenuOver));
  510     menu_button_->SetTooltip(GM_("SIDEBAR_MENU_BUTTON_TOOLTIP"));
  511     menu_button_->ConnectOnClickEvent(NewSlot(this, &Impl::OnMenuButtonClick));
  512 
  513     close_button_ = new ButtonElement(this, NULL);
  514     button_div->GetChildren()->InsertElement(close_button_, NULL);
  515     close_button_->SetImage(Variant(kSBButtonMinimizeUp));
  516     close_button_->SetDownImage(Variant(kSBButtonMinimizeDown));
  517     close_button_->SetOverImage(Variant(kSBButtonMinimizeOver));
  518     close_button_->SetTooltip(GM_("SIDEBAR_MINIMIZE_BUTTON_TOOLTIP"));
  519 
  520     Elements *buttons = button_div->GetChildren();
  521     double max_button_height = 0;
  522     double buttons_width = 0;
  523     for (size_t i = 0; i < 3; ++i) {
  524       BasicElement *button = buttons->GetItemByIndex(i);
  525       button->Layout();
  526       button->SetRelativePinY(0.5);
  527       button->SetRelativeY(0.5);
  528       button->SetPixelX(buttons_width);
  529       max_button_height = std::max(button->GetPixelHeight(), max_button_height);
  530       buttons_width += button->GetPixelWidth();
  531     }
  532     button_div->SetPixelWidth(buttons_width);
  533     top_div_->SetPixelHeight(
  534         std::max(google_icon_->GetSrcHeight(), max_button_height));
  535 
  536     main_div_ = new DivElement(this, NULL);
  537     GetChildren()->InsertElement(main_div_, NULL);
  538     main_div_->SetPixelX(kBorderWidth);
  539     main_div_->SetPixelY(top_div_->GetPixelY() + top_div_->GetPixelHeight());
  540     children_ = main_div_->GetChildren();
  541   }
  542 
  543   void OnMenuButtonClick() {
  544     view_host_->ShowContextMenu(MouseEvent::BUTTON_LEFT);
  545   }
  546 
  547   void InsertViewElement(size_t index, ViewElement *element) {
  548     ASSERT(index != kInvalidIndex);
  549     ASSERT(element);
  550     size_t count = children_->GetCount();
  551     if (initializing_) {
  552       for (size_t i = 0; i < count; ++i) {
  553         ViewElement *e = down_cast<ViewElement*>(children_->GetItemByIndex(i));
  554         View *v = e->GetChildView();
  555         if (v) {
  556           SideBarViewHost *vh = down_cast<SideBarViewHost*>(v->GetViewHost());
  557           if (index <= vh->GetInitialIndex()) {
  558             children_->InsertElement(element, e);
  559             element = NULL;
  560             break;
  561           }
  562         }
  563       }
  564       if (element)
  565         children_->InsertElement(element, NULL);
  566     } else {
  567       if (index >= count) {
  568         element->SetPixelY(main_div_->GetPixelHeight());
  569         children_->InsertElement(element, NULL);
  570       } else {
  571         BasicElement *e = children_->GetItemByIndex(index);
  572         if (e != element) {
  573           element->SetPixelY(e ? e->GetPixelY() : main_div_->GetPixelHeight());
  574           children_->InsertElement(element, e);
  575         }
  576       }
  577     }
  578     LayoutSubViews();
  579   }
  580 
  581   void RemoveViewElement(ViewElement *element) {
  582     children_->RemoveElement(element);
  583   }
  584 
  585   void LayoutSubViews() {
  586     double y = 0;
  587     size_t count = children_->GetCount();
  588     double sidebar_width = main_div_->GetPixelWidth();
  589     for (size_t i = 0; i < count; ++i) {
  590       ViewElement *e = down_cast<ViewElement *>(children_->GetItemByIndex(i));
  591       double width = sidebar_width;
  592       double height = ceil(e->GetPixelHeight());
  593       // Just ignore the OnSizing result, to set child view's width forcely.
  594       e->OnSizing(&width, &height);
  595       e->SetSize(sidebar_width, ceil(height));
  596       e->SetPixelX(0);
  597 
  598       double old_y = e->GetPixelY();
  599       double new_y = ceil(y);
  600       e->SetPixelY(new_y);
  601       View *child_view = e->GetChildView();
  602       if (old_y != new_y && child_view) {
  603         onview_moved_signal_(child_view);
  604       }
  605 
  606       if (e->IsVisible())
  607         y += e->GetPixelHeight();
  608       y += kGadgetSpacing;
  609     }
  610     QueueDraw();
  611   }
  612 
  613   // *offset could be any value
  614   bool UpResize(bool do_resize, size_t index, double *offset) {
  615     double sign = *offset > 0 ? 1 : -1;
  616     double count = 0;
  617     while (*offset * sign > count * sign && index != kInvalidIndex) {
  618       ViewElement *element =
  619           down_cast<ViewElement *>(children_->GetItemByIndex(index));
  620       double w = element->GetPixelWidth();
  621       double h = elements_height_[index] + count - *offset;
  622       // don't send non-positive resize request
  623       if (h <= .0) h = 1;
  624       if (element->OnSizing(&w, &h)) {
  625         double diff = std::min(sign * (elements_height_[index] - h),
  626                                sign * (*offset - count)) * sign;
  627         if (do_resize)
  628           element->SetSize(w, ceil(elements_height_[index] - diff));
  629         count += diff;
  630       } else {
  631         double oh = element->GetPixelHeight();
  632         double diff = std::min(sign * (elements_height_[index] - oh),
  633                                sign * (*offset - count)) * sign;
  634         if (diff > 0) count += diff;
  635       }
  636       index--;
  637     }
  638     if (do_resize) {
  639       // recover upmost elements' size
  640       while (index != kInvalidIndex) {
  641         ViewElement *element =
  642             down_cast<ViewElement *>(children_->GetItemByIndex(index));
  643         element->SetSize(main_div_->GetPixelWidth(), elements_height_[index]);
  644         index--;
  645       }
  646     }
  647     DLOG("original: at last off: %.1lf, count: %.1lf", *offset, count);
  648     if (count == 0) return false;
  649     *offset = count;
  650     return true;
  651   }
  652 
  653   bool DownResize(bool do_resize, size_t index, double *offset) {
  654     double count = 0;
  655     if (blank_height_ > 0) count = std::max(-blank_height_, *offset);
  656     while (*offset < count && index < children_->GetCount()) {
  657       ViewElement *element =
  658           down_cast<ViewElement *>(children_->GetItemByIndex(index));
  659       double w = element->GetPixelWidth();
  660       double h = elements_height_[index] + *offset - count;
  661       // don't send non-positive resize request
  662       if (h <= .0) h = 1;
  663       if (element->OnSizing(&w, &h) && h < elements_height_[index]) {
  664         double diff = std::min(elements_height_[index] - h, count - *offset);
  665         if (do_resize) {
  666           element->SetSize(w, ceil(elements_height_[index] - diff));
  667         }
  668         count -= diff;
  669       } else {
  670         double oh = element->GetPixelHeight();
  671         double diff = std::min(elements_height_[index] - oh, count - *offset);
  672         if (diff > 0) count -= diff;
  673       }
  674       index++;
  675     }
  676     if (do_resize) {
  677       // recover upmost elemnts' size
  678       while (index < children_->GetCount()) {
  679         ViewElement *element =
  680             down_cast<ViewElement *>(children_->GetItemByIndex(index));
  681         element->SetSize(main_div_->GetPixelWidth(), elements_height_[index]);
  682         index++;
  683       }
  684       LayoutSubViews();
  685     }
  686     if (count == 0) return false;
  687     *offset = count;
  688     return true;
  689   }
  690 
  691   double GetBlankHeight() const {
  692     size_t index = children_->GetCount();
  693     if (!index) return GetHeight();
  694     BasicElement *element = children_->GetItemByIndex(index - 1);
  695     return GetHeight() - element->GetPixelY() - element->GetPixelHeight();
  696   }
  697 
  698  public:
  699   SideBar *owner_;
  700   ViewHostInterface *view_host_;
  701   ViewElement *null_element_;
  702 
  703   std::vector<double> elements_height_;
  704   double blank_height_;
  705   double mouse_move_event_x_;
  706   double mouse_move_event_y_;
  707   bool hit_element_bottom_;
  708   bool hit_element_normal_part_;
  709   bool hit_sidebar_border_;
  710   HitTest hittest_;
  711 
  712   double original_width_;
  713   double original_height_;
  714 
  715   DivElement *top_div_;
  716   DivElement *main_div_;
  717   ImgElement *google_icon_;
  718   ButtonElement *add_gadget_button_;
  719   ButtonElement *menu_button_;
  720   ButtonElement *close_button_;
  721 
  722   Elements   *children_;
  723 
  724   bool initializing_;
  725 
  726   Signal4<void, View*, size_t, double, double> onundock_signal_;
  727   Signal1<void, View*> onclick_signal_;
  728   Signal1<void, MenuInterface *> onmenu_signal_;
  729   Signal1<void, View*> onview_moved_signal_;
  730 };
  731 
  732 SideBar::SideBar(ViewHostInterface *view_host)
  733   : impl_(new Impl(this, view_host)) {
  734 }
  735 
  736 SideBar::~SideBar() {
  737   delete impl_;
  738   impl_ = NULL;
  739 }
  740 
  741 void SideBar::SetInitializing(bool initializing) {
  742   impl_->initializing_ = initializing;
  743 }
  744 
  745 ViewHostInterface *SideBar::NewViewHost(size_t index) {
  746   return impl_->NewViewHost(index);
  747 }
  748 
  749 ViewHostInterface *SideBar::GetSideBarViewHost() const {
  750   return impl_->GetViewHost();
  751 }
  752 
  753 void SideBar::SetSize(double width, double height) {
  754   impl_->SetSize(width, height);
  755 }
  756 
  757 double SideBar::GetWidth() const {
  758   return impl_->GetWidth();
  759 }
  760 
  761 double SideBar::GetHeight() const {
  762   return impl_->GetHeight();
  763 }
  764 
  765 void SideBar::Show() {
  766   impl_->ShowView(false, 0, NULL);
  767 }
  768 
  769 void SideBar::Hide() {
  770   impl_->CloseView();
  771 }
  772 
  773 void SideBar::Minimize(bool vertical) {
  774   impl_->Minimize(vertical);
  775 }
  776 
  777 void SideBar::Restore() {
  778   impl_->Restore();
  779 }
  780 
  781 bool SideBar::IsMinimized() const {
  782   return impl_->IsMinimized();
  783 }
  784 
  785 size_t SideBar::GetIndexOfPosition(double y) const {
  786   return impl_->GetIndexOfPosition(y);
  787 }
  788 
  789 size_t SideBar::GetIndexOfView(const ViewInterface *view) const {
  790   return impl_->GetIndexOfView(view);
  791 }
  792 
  793 void SideBar::InsertPlaceholder(size_t index, double height) {
  794   return impl_->InsertPlaceholder(index, height);
  795 }
  796 
  797 void SideBar::ClearPlaceholder() {
  798   impl_->ClearPlaceholder();
  799 }
  800 
  801 void SideBar::EnumerateViews(Slot2<bool, size_t, View*> *slot) {
  802   impl_->EnumerateViews(slot);
  803 }
  804 
  805 Connection *SideBar::ConnectOnUndock(
  806     Slot4<void, View*, size_t, double, double> *slot) {
  807   return impl_->onundock_signal_.Connect(slot);
  808 }
  809 
  810 Connection *SideBar::ConnectOnClick(Slot1<void, View*> *slot) {
  811   return impl_->onclick_signal_.Connect(slot);
  812 }
  813 
  814 Connection *SideBar::ConnectOnAddGadget(Slot0<void> *slot) {
  815   return impl_->add_gadget_button_->ConnectOnClickEvent(slot);
  816 }
  817 
  818 Connection *SideBar::ConnectOnMenu(Slot1<void, MenuInterface *> *slot) {
  819   return impl_->onmenu_signal_.Connect(slot);
  820 }
  821 
  822 Connection *SideBar::ConnectOnClose(Slot0<void> *slot) {
  823   return impl_->close_button_->ConnectOnClickEvent(slot);
  824 }
  825 
  826 Connection *SideBar::ConnectOnSizeEvent(Slot0<void> *slot) {
  827   return impl_->ConnectOnSizeEvent(slot);
  828 }
  829 
  830 Connection *SideBar::ConnectOnViewMoved(Slot1<void, View *> *slot) {
  831   return impl_->onview_moved_signal_.Connect(slot);
  832 }
  833 
  834 Connection *SideBar::ConnectOnGoogleIconClicked(Slot0<void> *slot) {
  835   return impl_->google_icon_->ConnectOnClickEvent(slot);
  836 }
  837 
  838 }  // namespace ggadget