diff options
author | hbono@chromium.org <hbono@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-13 10:08:49 +0000 |
---|---|---|
committer | hbono@chromium.org <hbono@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-13 10:08:49 +0000 |
commit | ffff039aa96833fa805de9aa3b5a2379cfd28e33 (patch) | |
tree | 2eb1c10148cbc4513b1cc6084eb6a38254bc1fa3 /chrome/browser/ui/gtk/bubble/bubble_gtk.cc | |
parent | ed5f9c333bd10b3dd8ec5af9639e7e136f9fd519 (diff) | |
download | chromium_src-ffff039aa96833fa805de9aa3b5a2379cfd28e33.zip chromium_src-ffff039aa96833fa805de9aa3b5a2379cfd28e33.tar.gz chromium_src-ffff039aa96833fa805de9aa3b5a2379cfd28e33.tar.bz2 |
Allows to show bubble arrows to bottom.
This change adds ARROW_LOCATION_BOTTOM_LEFT, ARROW_LOCATION_BOTTOM_RIGHT, ARROW_LOCATION_NONE, and ARROW_LOCATION_FLOAT to BubbleGtk so A GTK bubble can show its arrow to the bottom and prevent showing arrows as BubbleDelegateView can.
BUG=99130
TEST=BubbleGtkTest.*
Review URL: http://codereview.chromium.org/9025003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@117625 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/ui/gtk/bubble/bubble_gtk.cc')
-rw-r--r-- | chrome/browser/ui/gtk/bubble/bubble_gtk.cc | 151 |
1 files changed, 121 insertions, 30 deletions
diff --git a/chrome/browser/ui/gtk/bubble/bubble_gtk.cc b/chrome/browser/ui/gtk/bubble/bubble_gtk.cc index c4c35a6..dc0f3c5 100644 --- a/chrome/browser/ui/gtk/bubble/bubble_gtk.cc +++ b/chrome/browser/ui/gtk/bubble/bubble_gtk.cc @@ -44,6 +44,32 @@ const int kRightMargin = kCornerSize - 1; const GdkColor kBackgroundColor = GDK_COLOR_RGB(0xff, 0xff, 0xff); const GdkColor kFrameColor = GDK_COLOR_RGB(0x63, 0x63, 0x63); +// Helper functions that encapsulate arrow locations. +bool HasArrow(BubbleGtk::ArrowLocationGtk location) { + return location != BubbleGtk::ARROW_LOCATION_NONE && + location != BubbleGtk::ARROW_LOCATION_FLOAT; +} + +bool IsArrowLeft(BubbleGtk::ArrowLocationGtk location) { + return location == BubbleGtk::ARROW_LOCATION_TOP_LEFT || + location == BubbleGtk::ARROW_LOCATION_BOTTOM_LEFT; +} + +bool IsArrowRight(BubbleGtk::ArrowLocationGtk location) { + return location == BubbleGtk::ARROW_LOCATION_TOP_RIGHT || + location == BubbleGtk::ARROW_LOCATION_BOTTOM_RIGHT; +} + +bool IsArrowTop(BubbleGtk::ArrowLocationGtk location) { + return location == BubbleGtk::ARROW_LOCATION_TOP_LEFT || + location == BubbleGtk::ARROW_LOCATION_TOP_RIGHT; +} + +bool IsArrowBottom(BubbleGtk::ArrowLocationGtk location) { + return location == BubbleGtk::ARROW_LOCATION_BOTTOM_LEFT || + location == BubbleGtk::ARROW_LOCATION_BOTTOM_RIGHT; +} + } // namespace // static @@ -197,7 +223,9 @@ std::vector<GdkPoint> BubbleGtk::MakeFramePolygonPoints( using gtk_util::MakeBidiGdkPoint; std::vector<GdkPoint> points; - bool on_left = (arrow_location == ARROW_LOCATION_TOP_LEFT); + int top_arrow_size = IsArrowTop(arrow_location) ? kArrowSize : 0; + int bottom_arrow_size = IsArrowBottom(arrow_location) ? kArrowSize : 0; + bool on_left = IsArrowLeft(arrow_location); // If we're stroking the frame, we need to offset some of our points by 1 // pixel. We do this when we draw horizontal lines that are on the bottom or @@ -211,37 +239,61 @@ std::vector<GdkPoint> BubbleGtk::MakeFramePolygonPoints( // Top left corner. points.push_back(MakeBidiGdkPoint( - x_off_r, kArrowSize + kCornerSize - 1, width, on_left)); - points.push_back(MakeBidiGdkPoint( - kCornerSize + x_off_r - 1, kArrowSize, width, on_left)); - - // The arrow. - points.push_back(MakeBidiGdkPoint( - kArrowX - kArrowSize + x_off_r, kArrowSize, width, on_left)); + x_off_r, top_arrow_size + kCornerSize - 1, width, on_left)); points.push_back(MakeBidiGdkPoint( - kArrowX + x_off_r, 0, width, on_left)); - points.push_back(MakeBidiGdkPoint( - kArrowX + 1 + x_off_l, 0, width, on_left)); - points.push_back(MakeBidiGdkPoint( - kArrowX + kArrowSize + 1 + x_off_l, kArrowSize, width, on_left)); + kCornerSize + x_off_r - 1, top_arrow_size, width, on_left)); + + // The top arrow. + if (top_arrow_size) { + points.push_back(MakeBidiGdkPoint( + kArrowX - top_arrow_size + x_off_r, top_arrow_size, width, on_left)); + points.push_back(MakeBidiGdkPoint( + kArrowX + x_off_r, 0, width, on_left)); + points.push_back(MakeBidiGdkPoint( + kArrowX + 1 + x_off_l, 0, width, on_left)); + points.push_back(MakeBidiGdkPoint( + kArrowX + top_arrow_size + 1 + x_off_l, top_arrow_size, + width, on_left)); + } // Top right corner. points.push_back(MakeBidiGdkPoint( - width - kCornerSize + 1 + x_off_l, kArrowSize, width, on_left)); + width - kCornerSize + 1 + x_off_l, top_arrow_size, width, on_left)); points.push_back(MakeBidiGdkPoint( - width + x_off_l, kArrowSize + kCornerSize - 1, width, on_left)); + width + x_off_l, top_arrow_size + kCornerSize - 1, width, on_left)); // Bottom right corner. points.push_back(MakeBidiGdkPoint( - width + x_off_l, height - kCornerSize, width, on_left)); + width + x_off_l, height - bottom_arrow_size - kCornerSize, + width, on_left)); points.push_back(MakeBidiGdkPoint( - width - kCornerSize + x_off_r, height + y_off, width, on_left)); + width - kCornerSize + x_off_r, height - bottom_arrow_size + y_off, + width, on_left)); + + // The bottom arrow. + if (bottom_arrow_size) { + points.push_back(MakeBidiGdkPoint( + kArrowX + bottom_arrow_size + 1 + x_off_l, + height - bottom_arrow_size + y_off, + width, + on_left)); + points.push_back(MakeBidiGdkPoint( + kArrowX + 1 + x_off_l, height + y_off, width, on_left)); + points.push_back(MakeBidiGdkPoint( + kArrowX + x_off_r, height + y_off, width, on_left)); + points.push_back(MakeBidiGdkPoint( + kArrowX - bottom_arrow_size + x_off_r, + height - bottom_arrow_size + y_off, + width, + on_left)); + } // Bottom left corner. points.push_back(MakeBidiGdkPoint( - kCornerSize + x_off_l, height + y_off, width, on_left)); + kCornerSize + x_off_l, height -bottom_arrow_size + y_off, + width, on_left)); points.push_back(MakeBidiGdkPoint( - x_off_r, height - kCornerSize, width, on_left)); + x_off_r, height - bottom_arrow_size - kCornerSize, width, on_left)); return points; } @@ -249,20 +301,46 @@ std::vector<GdkPoint> BubbleGtk::MakeFramePolygonPoints( BubbleGtk::ArrowLocationGtk BubbleGtk::GetArrowLocation( ArrowLocationGtk preferred_location, int arrow_x, - int width) { - bool wants_left = (preferred_location == ARROW_LOCATION_TOP_LEFT); + int arrow_y, + int width, + int height) { int screen_width = gdk_screen_get_width(gdk_screen_get_default()); + int screen_height = gdk_screen_get_height(gdk_screen_get_default()); + + // Choose whether we should show this bubble above the specified location or + // below it. + bool wants_top = IsArrowTop(preferred_location) || + preferred_location == ARROW_LOCATION_NONE; + bool top_is_onscreen = (arrow_y + height < screen_height); + bool bottom_is_onscreen = (arrow_y - height >= 0); + + ArrowLocationGtk arrow_location_none; + ArrowLocationGtk arrow_location_left; + ArrowLocationGtk arrow_location_right; + if (top_is_onscreen && (wants_top || !bottom_is_onscreen)) { + arrow_location_none = ARROW_LOCATION_NONE; + arrow_location_left = ARROW_LOCATION_TOP_LEFT; + arrow_location_right =ARROW_LOCATION_TOP_RIGHT; + } else { + arrow_location_none = ARROW_LOCATION_FLOAT; + arrow_location_left = ARROW_LOCATION_BOTTOM_LEFT; + arrow_location_right =ARROW_LOCATION_BOTTOM_RIGHT; + } + if (!HasArrow(preferred_location)) + return arrow_location_none; + + bool wants_left = IsArrowLeft(preferred_location); bool left_is_onscreen = (arrow_x - kArrowX + width < screen_width); bool right_is_onscreen = (arrow_x + kArrowX - width >= 0); // Use the requested location if it fits onscreen, use whatever fits // otherwise, and use the requested location if neither fits. if (left_is_onscreen && (wants_left || !right_is_onscreen)) - return ARROW_LOCATION_TOP_LEFT; + return arrow_location_left; if (right_is_onscreen && (!wants_left || !left_is_onscreen)) - return ARROW_LOCATION_TOP_RIGHT; - return (wants_left ? ARROW_LOCATION_TOP_LEFT : ARROW_LOCATION_TOP_RIGHT); + return arrow_location_right; + return (wants_left ? arrow_location_left : arrow_location_right); } bool BubbleGtk::UpdateArrowLocation(bool force_move_and_reshape) { @@ -282,7 +360,9 @@ bool BubbleGtk::UpdateArrowLocation(bool force_move_and_reshape) { current_arrow_location_ = GetArrowLocation( preferred_arrow_location_, toplevel_x + offset_x + (rect_.width() / 2), // arrow_x - allocation.width); + toplevel_y + offset_y, + allocation.width, + allocation.height); if (force_move_and_reshape || current_arrow_location_ != old_location) { UpdateWindowShape(); @@ -325,10 +405,16 @@ void BubbleGtk::MoveWindow() { gtk_widget_translate_coordinates(anchor_widget_, toplevel_window_, rect_.x(), rect_.y(), &offset_x, &offset_y); + GtkAllocation allocation; + gtk_widget_get_allocation(window_, &allocation); + gint screen_x = 0; - if (current_arrow_location_ == ARROW_LOCATION_TOP_LEFT) { + if (!HasArrow(current_arrow_location_)) { + screen_x = + toplevel_x + offset_x + (rect_.width() / 2) - allocation.width / 2; + } else if (IsArrowLeft(current_arrow_location_)) { screen_x = toplevel_x + offset_x + (rect_.width() / 2) - kArrowX; - } else if (current_arrow_location_ == ARROW_LOCATION_TOP_RIGHT) { + } else if (IsArrowRight(current_arrow_location_)) { GtkAllocation allocation; gtk_widget_get_allocation(window_, &allocation); screen_x = toplevel_x + offset_x + (rect_.width() / 2) - @@ -337,8 +423,13 @@ void BubbleGtk::MoveWindow() { NOTREACHED(); } - gint screen_y = toplevel_y + offset_y + rect_.height() + - kArrowToContentPadding; + gint screen_y = toplevel_y + offset_y + rect_.height(); + if (IsArrowTop(current_arrow_location_) || + current_arrow_location_ == ARROW_LOCATION_NONE) { + screen_y += kArrowToContentPadding; + } else { + screen_y -= allocation.height + kArrowToContentPadding; + } gtk_window_move(GTK_WINDOW(window_), screen_x, screen_y); } @@ -483,7 +574,7 @@ void BubbleGtk::OnSizeAllocate(GtkWidget* widget, GtkAllocation* allocation) { if (!UpdateArrowLocation(false)) { UpdateWindowShape(); - if (current_arrow_location_ == ARROW_LOCATION_TOP_RIGHT) + if (current_arrow_location_ != ARROW_LOCATION_TOP_LEFT) MoveWindow(); } } |