diff options
| author | Brandon Schaefer <brandon.schaefer@canonical.com> | 2012-11-13 13:42:58 -0800 |
|---|---|---|
| committer | Brandon Schaefer <brandon.schaefer@canonical.com> | 2012-11-13 13:42:58 -0800 |
| commit | b4fdb26d5508211b60ebf6e5e353e1389ba41114 (patch) | |
| tree | 4845ba5e27eebe5774b3887a564530d32a85803a /unity-shared | |
| parent | 51a7bae949ddd380bba052e60d7ca19745a3c4ae (diff) | |
* Adds overlayscroll bar
(bzr r2892.5.1)
Diffstat (limited to 'unity-shared')
| -rw-r--r-- | unity-shared/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | unity-shared/PlacesOverlayVScrollBar.cpp | 262 | ||||
| -rw-r--r-- | unity-shared/PlacesOverlayVScrollBar.h | 89 | ||||
| -rw-r--r-- | unity-shared/VScrollBarOverlayWindow.cpp | 521 | ||||
| -rw-r--r-- | unity-shared/VScrollBarOverlayWindow.h | 91 |
5 files changed, 965 insertions, 0 deletions
diff --git a/unity-shared/CMakeLists.txt b/unity-shared/CMakeLists.txt index 0c39967d1..d87678d58 100644 --- a/unity-shared/CMakeLists.txt +++ b/unity-shared/CMakeLists.txt @@ -47,6 +47,7 @@ set (UNITY_SHARED_SOURCES OverlayRenderer.cpp PanelStyle.cpp PlacesVScrollBar.cpp + PlacesOverlayVScrollBar.cpp PreviewStyle.cpp RatingsButton.cpp SearchBar.cpp @@ -64,6 +65,7 @@ set (UNITY_SHARED_SOURCES UnityWindowStyle.cpp UnityWindowView.cpp UserThumbnailProvider.cpp + VScrollBarOverlayWindow.cpp WindowManager.cpp ) diff --git a/unity-shared/PlacesOverlayVScrollBar.cpp b/unity-shared/PlacesOverlayVScrollBar.cpp new file mode 100644 index 000000000..84d1d6d57 --- /dev/null +++ b/unity-shared/PlacesOverlayVScrollBar.cpp @@ -0,0 +1,262 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Authored by: Brandon Schaefer <brandon.schaefer@canonical.com> + */ + +#include <Nux/Nux.h> +#include <NuxCore/EasingCurve.h> + +#include "PlacesOverlayVScrollBar.h" + +namespace unity +{ +namespace dash +{ + +PlacesOverlayVScrollBar::PlacesOverlayVScrollBar(NUX_FILE_LINE_DECL) + : PlacesVScrollBar(NUX_FILE_LINE_PARAM) + , _mouse_down_offset(0) +{ + _overlay_window = new VScrollBarOverlayWindow(_track->GetAbsoluteGeometry()); + + _prox_area = std::make_shared<nux::ProximityArea>(_overlay_window.GetPointer(), 7); + _prox_area->mouse_near.connect(sigc::mem_fun(this, &PlacesOverlayVScrollBar::OnMouseNear)); + _prox_area->mouse_beyond.connect(sigc::mem_fun(this, &PlacesOverlayVScrollBar::OnMouseBeyond)); + + _overlay_window->mouse_down.connect(sigc::mem_fun(this, &PlacesOverlayVScrollBar::OnMouseDown)); + _overlay_window->mouse_up.connect(sigc::mem_fun(this, &PlacesOverlayVScrollBar::OnMouseUp)); + _overlay_window->mouse_click.connect(sigc::mem_fun(this, &PlacesOverlayVScrollBar::OnMouseClick)); + _overlay_window->mouse_move.connect(sigc::mem_fun(this, &PlacesOverlayVScrollBar::OnMouseMove)); + _overlay_window->mouse_drag.connect(sigc::mem_fun(this, &PlacesOverlayVScrollBar::OnMouseDrag)); + + _track->geometry_changed.connect([&] (nux::Area* area, nux::Geometry& geo) { + UpdateStepY(); + _overlay_window->UpdateGeometry(_track->GetAbsoluteGeometry()); + }); + + OnVisibleChanged.connect([&] (nux::Area* area, bool visible) { + _overlay_window->SetVisible(visible); + }); + +} + +PlacesOverlayVScrollBar::~PlacesOverlayVScrollBar() +{ + _overlay_window.Release(); +} + +void PlacesOverlayVScrollBar::SetupAnimation(ScrollDir dir, int stop) +{ + if (_animation.CurrentState() == nux::animation::Animation::State::Stopped) + { + _tweening_connection.disconnect(); + + _animation.SetDuration(400); + _animation.SetEasingCurve(nux::animation::EasingCurve(nux::animation::EasingCurve::Type::Linear)); + + _animation.SetStartValue(0); + _animation.SetFinishValue(stop); + + StartAnimation(dir); + } +} + +void PlacesOverlayVScrollBar::StartAnimation(ScrollDir dir) +{ + _tweening_connection = _animation.updated.connect([this, dir] (const int& update) { + static int delta_update = 0; + + OnScroll(dir, update - delta_update); + delta_update = update; + + CheckIfThumbIsInsideSlider(); + QueueDraw(); + if (update == _animation.GetFinishValue()) + delta_update = 0; + }); + + _animation.Start(); +} + +void PlacesOverlayVScrollBar::OnScroll(ScrollDir dir, int mouse_dy) +{ + if (dir == ScrollDir::UP) + OnScrollUp.emit(stepY, mouse_dy); + else if (dir == ScrollDir::DOWN) + OnScrollDown.emit(stepY, mouse_dy); +} + +void PlacesOverlayVScrollBar::OnMouseNear(nux::Point mouse_pos) +{ + if (content_height_ > container_height_) + { + _overlay_window->MouseNear(); + AdjustThumbOffsetFromMouse(); + } +} + +void PlacesOverlayVScrollBar::OnMouseBeyond(nux::Point mouse_pos) +{ + if (content_height_ > container_height_) + _overlay_window->MouseBeyond(); +} + +void PlacesOverlayVScrollBar::AdjustThumbOffsetFromMouse() +{ + const nux::Point& mouse = nux::GetWindowCompositor().GetMousePosition(); + const int new_offset = mouse.y - _track->GetAbsoluteY() - _overlay_window->GetThumbHeight()/2; + + const int slider_offset = _slider->GetBaseY() - _track->GetBaseY(); + const bool thumb_above_slider = slider_offset < new_offset; + + if (thumb_above_slider) + _overlay_window->SetThumbOffsetY(new_offset - _overlay_window->GetThumbHeight()/4); + else + _overlay_window->SetThumbOffsetY(new_offset + _overlay_window->GetThumbHeight()/4); + + CheckIfThumbIsInsideSlider(); +} + +void PlacesOverlayVScrollBar::CheckIfThumbIsInsideSlider() +{ + const nux::Geometry& slider_geo = _slider->GetAbsoluteGeometry(); + const nux::Geometry& thumb_geo = _overlay_window->GetThumbGeometry(); + const nux::Geometry& intersection = (thumb_geo.Intersect(slider_geo)); + + if (!intersection.IsNull()) + _overlay_window->ThumbInsideSlider(); + else + _overlay_window->ThumbOutsideSlider(); +} + +void PlacesOverlayVScrollBar::OnMouseClick(int x, int y, unsigned int button_flags, unsigned int key_flags) +{ + if (!_overlay_window->IsMouseBeingDragged()) + { + const int button = nux::GetEventButton(button_flags); + + if (button == 1) + LeftMouseClick(y); + else if (button == 2) + MiddleMouseClick(y); + } + + _overlay_window->MouseUp(); +} + +void PlacesOverlayVScrollBar::LeftMouseClick(int y) +{ + if (IsMouseInTopHalfOfThumb(y)) + SetupAnimation(ScrollDir::UP, _slider->GetBaseHeight()); + else + SetupAnimation(ScrollDir::DOWN, _slider->GetBaseHeight()); +} + +void PlacesOverlayVScrollBar::MiddleMouseClick(int y) +{ + const int slider_offset = _slider->GetBaseY() - _track->GetBaseY(); + const bool move_up = slider_offset > _overlay_window->GetThumbOffsetY(); + + const int slider_thumb_diff = abs(_overlay_window->GetThumbOffsetY() - slider_offset); + + if (move_up) + SetupAnimation(ScrollDir::UP, slider_thumb_diff); + else + SetupAnimation(ScrollDir::DOWN, slider_thumb_diff); + + //FIXME LOOK into making sure slider_offset == thumb offset +} + +void PlacesOverlayVScrollBar::OnMouseDown(int x, int y, unsigned int button_flags, unsigned int key_flags) +{ + if (_overlay_window->IsMouseInsideThumb(x, y)) + { + if (IsMouseInTopHalfOfThumb(y)) + _overlay_window->PageUpAction(); + else + _overlay_window->PageDownAction(); + + _mouse_down_offset = y - _overlay_window->GetThumbOffsetY(); + _overlay_window->MouseDown(); + } +} + +bool PlacesOverlayVScrollBar::IsMouseInTopHalfOfThumb(int y) +{ + const int thumb_height = _overlay_window->GetThumbHeight(); + const int thumb_offset_y = _overlay_window->GetThumbOffsetY(); + + if (y < (thumb_height/2 + thumb_offset_y)) + return true; + + return false; +} + +void PlacesOverlayVScrollBar::OnMouseUp(int x, int y, unsigned int button_flags, unsigned int key_flags) +{ + const nux::Geometry& geo = _overlay_window->GetAbsoluteGeometry(); + + if (!geo.IsPointInside(x + geo.x, y + geo.y)) + _overlay_window->MouseUp(); +} + +void PlacesOverlayVScrollBar::OnMouseMove(int x, int y, int dx, int dy, unsigned int button_flags, unsigned int key_flags) +{ + if (!_overlay_window->IsMouseInsideThumb(x,y)) + AdjustThumbOffsetFromMouse(); +} + +void PlacesOverlayVScrollBar::OnMouseDrag(int x, int y, int dx, int dy, unsigned int button_flags, unsigned int key_flags) +{ + if (IsMouseInTrackRange(y)) + MouseDraggingOverlay(y, dy); +} + +bool PlacesOverlayVScrollBar::IsMouseInTrackRange(int y) +{ + const int thumbs_height = _overlay_window->GetThumbHeight(); + const int thumbs_offset = _overlay_window->GetThumbOffsetY(); + + if ((y < 0 && _overlay_window->GetThumbOffsetY() <= 0) || + (y > _track->GetBaseHeight() && thumbs_height + thumbs_offset >= _track->GetBaseHeight())) + { + return false; + } + + return true; +} + +void PlacesOverlayVScrollBar::MouseDraggingOverlay(int y, int dys) +{ + int dy = y - _overlay_window->GetThumbOffsetY() - _mouse_down_offset; + if (dy < 0) + OnScrollUp.emit(stepY, abs(dy)); + else if (dy > 0) + OnScrollDown.emit(stepY, dy); + + _overlay_window->SetThumbOffsetY(y - _mouse_down_offset); + CheckIfThumbIsInsideSlider(); +} + +void PlacesOverlayVScrollBar::UpdateStepY() +{ + stepY = (float) (content_height_ - container_height_) / (float) (_track->GetBaseHeight() - _slider->GetBaseHeight()); +} + +} // namespace dash +} // namespace unity + diff --git a/unity-shared/PlacesOverlayVScrollBar.h b/unity-shared/PlacesOverlayVScrollBar.h new file mode 100644 index 000000000..542b0bfef --- /dev/null +++ b/unity-shared/PlacesOverlayVScrollBar.h @@ -0,0 +1,89 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Authored by: Brandon Schaefer <brandon.schaefer@canonical.com> + */ + +#ifndef PLACES_OVERLAY_VSCROLLBAR_H +#define PLACES_OVERLAY_VSCROLLBAR_H + +#include <Nux/Nux.h> +#include <Nux/ProximityArea.h> +#include <NuxCore/Animation.h> +#include <memory> + +#include "unity-shared/PlacesVScrollBar.h" +#include "unity-shared/VScrollBarOverlayWindow.h" + +namespace unity +{ +namespace dash +{ + +class PlacesOverlayVScrollBar: public PlacesVScrollBar +{ +public: + PlacesOverlayVScrollBar(NUX_FILE_LINE_PROTO); + ~PlacesOverlayVScrollBar(); + +private: + enum class ScrollDir : unsigned int + { + UP, + DOWN, + }; + + void OnMouseNear(nux::Point mouse_pos); + void OnMouseBeyond(nux::Point mouse_pos); + void AdjustThumbOffsetFromMouse(); + + void OnMouseClick(int x, int y, unsigned int button_flags, unsigned int key_flags); + void LeftMouseClick(int y); + void MiddleMouseClick(int y); + + void OnMouseDown(int x, int y, unsigned int button_flags, unsigned int key_flags); + void OnMouseUp(int x, int y, unsigned int button_flags, unsigned int key_flags); + + void OnMouseMove(int x, int y, int dx, int dy, unsigned int button_flags, unsigned int key_flags); + + void OnMouseDrag(int x, int y, int dx, int dy, unsigned int button_flags, unsigned int key_flags); + void MouseDraggingOverlay(int y, int dy); + + bool IsMouseInTopHalfOfThumb(int y); + bool IsMouseInTrackRange(int y); + + void CheckIfThumbIsInsideSlider(); + + void UpdateStepY(); + + void SetupAnimation(ScrollDir dir, int stop); + void StartAnimation(ScrollDir dir); + void OnScroll(ScrollDir dir, int mouse_dy); + +private: + nux::ObjectPtr<VScrollBarOverlayWindow> _overlay_window; + std::shared_ptr<nux::ProximityArea> _prox_area; + + nux::animation::AnimateValue<int> _animation; + sigc::connection _tweening_connection; + + int _mouse_down_offset; +}; + +} // namespace dash +} // namespace unity + +#endif // PLACES_OVERLAY_VSCROLLBAR_H diff --git a/unity-shared/VScrollBarOverlayWindow.cpp b/unity-shared/VScrollBarOverlayWindow.cpp new file mode 100644 index 000000000..668fd954a --- /dev/null +++ b/unity-shared/VScrollBarOverlayWindow.cpp @@ -0,0 +1,521 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2012 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Authored by: Brandon Schaefer <brandon.schaefer@canonical.com> + */ + +#include <Nux/Nux.h> +#include <Nux/ProximityArea.h> +#include <Nux/VScrollBar.h> +#include <NuxGraphics/CairoGraphics.h> + +#include "VScrollBarOverlayWindow.h" +#include "UScreen.h" +#include "UBusMessages.h" +#include "DashStyle.h" +#include "CairoTexture.h" + +const int THUMB_WIDTH = 21; +const int THUMB_HEIGHT = 68; +const int THUMB_RADIUS = 3; + + +VScrollBarOverlayWindow::VScrollBarOverlayWindow(const nux::Geometry geo) + : nux::BaseWindow("") + , content_size_(geo) + , content_offset_x_(0) + , mouse_offset_y_(0) + , mouse_down_(false) + , mouse_near_(false) + , inside_slider_(false) + , current_action_(ThumbAction::NONE) +{ + Area::SetGeometry(content_size_.x, content_size_.y, THUMB_WIDTH, content_size_.height); + SetBackgroundColor(nux::color::Transparent); + + UpdateTexture(); + + _ubus_manager.RegisterInterest(UBUS_OVERLAY_HIDDEN, sigc::mem_fun(this, &VScrollBarOverlayWindow::OnOverlayHidden)); +} + +VScrollBarOverlayWindow::~VScrollBarOverlayWindow() +{ + if(thumb_texture_) + thumb_texture_.Release(); +} + +void VScrollBarOverlayWindow::UpdateGeometry(const nux::Geometry& geo) +{ + content_size_ = geo; + UpdateMouseOffsetX(); + Area::SetGeometry(content_size_.x + content_offset_x_, content_size_.y, THUMB_WIDTH, content_size_.height); +} + +void VScrollBarOverlayWindow::SetThumbOffsetY(int y) +{ + if (mouse_down_) + MouseDragging(); + + mouse_offset_y_ = GetValidOffsetYValue(y); + QueueDraw(); +} + +int VScrollBarOverlayWindow::GetValidOffsetYValue(int new_offset) const +{ + if (new_offset < 0) + return 0; + else if (new_offset > content_size_.height - THUMB_HEIGHT) + return content_size_.height - THUMB_HEIGHT; + + return new_offset; +} + +void VScrollBarOverlayWindow::UpdateMouseOffsetX() +{ + int monitor = unity::UScreen::GetDefault()->GetMonitorWithMouse(); + const nux::Geometry& geo = unity::UScreen::GetDefault()->GetMonitorGeometry(monitor); + + if (content_size_.x + THUMB_WIDTH > geo.width) + content_offset_x_ = geo.width - (content_size_.x + THUMB_WIDTH) + 1; + else + content_offset_x_ = 0; +} + +bool VScrollBarOverlayWindow::IsMouseInsideThumb(int x, int y) const +{ + const nux::Geometry thumb(0, mouse_offset_y_, THUMB_WIDTH, THUMB_HEIGHT); + if (thumb.IsPointInside(x,y)) + return true; + + return false; +} + +bool VScrollBarOverlayWindow::IsMouseBeingDragged() const +{ + return current_action_ == ThumbAction::DRAGGING; +} + +int VScrollBarOverlayWindow::GetThumbHeight() const +{ + return THUMB_HEIGHT; +} + +int VScrollBarOverlayWindow::GetThumbOffsetY() const +{ + return mouse_offset_y_; +} + +nux::Geometry VScrollBarOverlayWindow::GetThumbGeometry() const +{ + return nux::Geometry(content_size_.x + content_offset_x_, + content_size_.y + mouse_offset_y_, + THUMB_WIDTH, THUMB_HEIGHT); +} + +void VScrollBarOverlayWindow::MouseDown() +{ + mouse_down_ = true; + UpdateTexture(); +} + +void VScrollBarOverlayWindow::MouseUp() +{ + mouse_down_ = false; + current_action_ = ThumbAction::NONE; + UpdateTexture(); + ShouldHide(); +} + +void VScrollBarOverlayWindow::MouseNear() +{ + mouse_near_ = true; + ShouldShow(); +} + +void VScrollBarOverlayWindow::MouseBeyond() +{ + mouse_near_ = false; + ShouldHide(); +} + +void VScrollBarOverlayWindow::ThumbInsideSlider() +{ + if (!inside_slider_) + { + inside_slider_ = true; + UpdateTexture(); + } +} + +void VScrollBarOverlayWindow::ThumbOutsideSlider() +{ + if (inside_slider_) + { + inside_slider_ = false; + UpdateTexture(); + } +} + +void VScrollBarOverlayWindow::PageUpAction() +{ + current_action_ = ThumbAction::PAGE_UP; + UpdateTexture(); +} + +void VScrollBarOverlayWindow::PageDownAction() +{ + current_action_ = ThumbAction::PAGE_DOWN; + UpdateTexture(); +} + +void VScrollBarOverlayWindow::MouseDragging() +{ + if (current_action_ != ThumbAction::DRAGGING) + { + current_action_ = ThumbAction::DRAGGING; + UpdateTexture(); + } +} + +void VScrollBarOverlayWindow::ShouldShow() +{ + if (!IsVisible()) + { + if (mouse_down_ || mouse_near_) + { + ShowWindow(true); + PushToFront(); + QueueDraw(); + } + } +} + +void VScrollBarOverlayWindow::ShouldHide() +{ + if (IsVisible()) + { + if (!mouse_down_ && !mouse_near_) + { + ShowWindow(false); + QueueDraw(); + } + } +} + +void VScrollBarOverlayWindow::OnOverlayHidden(GVariant* data) +{ + ResetStates(); +} + +void VScrollBarOverlayWindow::ResetStates() +{ + mouse_down_ = false; + mouse_near_ = false; + current_action_ = ThumbAction::NONE; + ShouldHide(); +} + +void VScrollBarOverlayWindow::DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw) +{ + nux::Color color = nux::color::White; + nux::Geometry base = content_size_; + base.SetX(0); + base.SetY(mouse_offset_y_); + base.SetWidth(THUMB_WIDTH); + base.SetHeight(THUMB_HEIGHT); + + nux::TexCoordXForm texxform; + + if (!thumb_texture_) + return; + + graphics_engine.QRP_1Tex(base.x, + base.y, + base.width, + base.height, + thumb_texture_->GetDeviceTexture(), + texxform, + color); +} + +nux::Color ProduceColorShade(const nux::Color& color, float shade) +{ + if (shade == 1.0f) + return color; + + nux::color::HueLightnessSaturation hls(color); + + hls.lightness *= shade; + if (hls.lightness > 1.0f) + hls.lightness = 1.0f; + else if (hls.lightness < 0.0f) + hls.lightness = 0.0f; + + hls.saturation *= shade; + if (hls.saturation > 1.0f) + hls.saturation = 1.0f; + else if (hls.saturation < 0.0f) + hls.saturation = 0.0f; + + nux::color::RedGreenBlue rgb_shade(hls); + nux::Color rgba_shade(rgb_shade, color.alpha); + + return rgba_shade; +} + +void PatternAddRGBStop(cairo_pattern_t* pat, const nux::Color& color, double stop, float alpha) +{ + cairo_pattern_add_color_stop_rgba (pat, stop, color.red, color.green, color.blue, alpha); +} + +void SetSourceRGB(cairo_t* cr, const nux::Color& color, float alpha) +{ + cairo_set_source_rgba(cr, color.red, color.green, color.blue, alpha); +} + +void DrawGrip (cairo_t* cr, double x, double y, int nx, int ny) +{ + gint lx, ly; + + for (ly = 0; ly < ny; ly++) + { + for (lx = 0; lx < nx; lx++) + { + gint sx = lx * 3; + gint sy = ly * 3; + + cairo_rectangle (cr, x + sx, y + sy, 1, 1); + } + } +} + +void DrawBothGrips(cairo_t* cr, const nux::Color& color, int width, int height) +{ + cairo_pattern_t* pat; + + pat = cairo_pattern_create_linear(0, 0, 0, height); + + PatternAddRGBStop(pat, color, 0.0, 0.0); + PatternAddRGBStop(pat, color, 0.49, 0.5); + PatternAddRGBStop(pat, color, 0.49, 0.5); + PatternAddRGBStop(pat, color, 1.0, 0.0); + + cairo_set_source(cr, pat); + cairo_pattern_destroy(pat); + + DrawGrip(cr, width/2 - 6.5, 13.5, 5, 6); + DrawGrip(cr, width/2 - 6.5, height/2 + 3.5, 5, 6); + + cairo_fill(cr); +} + +void DrawLineSeperator(cairo_t* cr, const nux::Color& top, const nux::Color& bottom, int width, int height) +{ + // Top + cairo_move_to(cr, 1.5, height/2); + cairo_line_to(cr, width - 1.5, height/2); + SetSourceRGB(cr, top, 0.36); + cairo_stroke(cr); + + // Bottom + cairo_move_to(cr, 1.5, 1 + height/2); + cairo_line_to(cr, width - 1.5, 1 + height/2); + SetSourceRGB(cr, bottom, 0.5); + cairo_stroke(cr); +} + + +void DrawArrow (cairo_t* cr, const nux::Color color, double x, double y, double width, double height) +{ + cairo_save (cr); + + cairo_translate (cr, x, y); + cairo_move_to (cr, -width / 2, -height / 2); + cairo_line_to (cr, 0, height / 2); + cairo_line_to (cr, width / 2, -height / 2); + cairo_close_path (cr); + + SetSourceRGB(cr, color, 0.75); + cairo_fill_preserve (cr); + + SetSourceRGB(cr, color, 1.0); + cairo_stroke (cr); + + cairo_restore (cr); +} + +void DrawBothArrows(cairo_t* cr, int width, int height) +{ + nux::Color arrow_color(0.3f, 0.3f, 0.3f, 1.0f); + + // Top + cairo_save(cr); + cairo_translate(cr, width/2 + 0.5, 8.5); + cairo_rotate(cr, G_PI); + DrawArrow(cr, arrow_color, 0.5, 0, 5, 3); + cairo_restore(cr); + + // Bottom + cairo_save(cr); + cairo_translate(cr, width/2 + 0.5, height - 8.5); + cairo_rotate(cr, 0); + DrawArrow(cr, arrow_color, -0.5, 0, 5, 3); + cairo_restore(cr); +} + +void VScrollBarOverlayWindow::UpdateTexture() +{ + int width = THUMB_WIDTH; + int height = THUMB_HEIGHT; + int radius = THUMB_RADIUS; + + nux::CairoGraphics* cairoGraphics = NULL; + cairo_t* cr = NULL; + cairo_pattern_t* pat = NULL; + + nux::Color bg(0.91f, 0.90f, 0.90f, 1.00f); + nux::Color bg_selected(0.95f, 0.95f, 0.95f, 1.0f); + nux::Color bg_active(0.55f, 0.55f, 0.55f, 0.8f); + + cairoGraphics = new nux::CairoGraphics(CAIRO_FORMAT_ARGB32, width, height); + cr = cairoGraphics->GetContext(); + + cairo_save(cr); + + cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); + cairo_paint(cr); + + cairo_save(cr); + + cairo_translate (cr, 0.5, 0.5); + width--; + height--; + + cairo_set_line_width (cr, 1.0); + + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + cairo_save(cr); + + // Draw backgound + SetSourceRGB(cr, bg, 1.0); + cairoGraphics->DrawRoundedRectangle(cr, 1.0f, 0.0, 0.0, radius, width, height); + cairo_fill_preserve(cr); + + // Draw shaded background + pat = cairo_pattern_create_linear(0, 0, 0, height); + + nux::Color bg_arrow_up = ProduceColorShade(bg, 0.86); + nux::Color bg_arrow_down = ProduceColorShade(bg, 1.1); + + PatternAddRGBStop(pat, bg_arrow_up, 0.0, 0.8); + PatternAddRGBStop(pat, bg_arrow_down, 1.0, 0.8); + + cairo_set_source(cr, pat); + cairo_pattern_destroy(pat); + + if (current_action_ == ThumbAction::DRAGGING) + { + cairo_fill_preserve(cr); + SetSourceRGB(cr, bg, 0.8); + cairo_fill(cr); + } + else + { + cairo_fill(cr); + } + + // Draw Page Up/Down Action + if (current_action_ == ThumbAction::PAGE_UP || + current_action_ == ThumbAction::PAGE_DOWN) + { + if (current_action_ == ThumbAction::PAGE_UP) + cairo_rectangle(cr, 0, 0, width, height/2); + else + cairo_rectangle(cr, 0, height/2, width, height/2); + + SetSourceRGB(cr, bg, 0.8); + cairo_fill(cr); + } + + cairo_save(cr); + + // Draw Outline + cairo_set_line_width (cr, 2.0); + cairoGraphics->DrawRoundedRectangle(cr, 1.0f, 0.5, 0.5, radius - 1, width - 1, height - 1); + + if (inside_slider_) + SetSourceRGB(cr, bg_selected, 1.0); + else + SetSourceRGB(cr, bg_active, 0.9); + + cairo_stroke(cr); + + cairo_restore(cr); + + // Draw shade outline + pat = cairo_pattern_create_linear(0, 0, 0, height); + + nux::Color bg_shadow = ProduceColorShade(bg, 0.2); + PatternAddRGBStop(pat, bg_shadow, 0.5, 0.06); + + switch(current_action_) + { + case ThumbAction::NONE: + PatternAddRGBStop(pat, bg_shadow, 0.0, 0.22); + PatternAddRGBStop(pat, bg_shadow, 1.0, 0.22); + break; + case ThumbAction::DRAGGING: + PatternAddRGBStop(pat, bg_shadow, 0.0, 0.2); + PatternAddRGBStop(pat, bg_shadow, 1.0, 0.2); + break; + case ThumbAction::PAGE_UP: + PatternAddRGBStop(pat, bg_shadow, 0.0, 0.1); + PatternAddRGBStop(pat, bg_shadow, 1.0, 0.22); + break; + case ThumbAction::PAGE_DOWN: + PatternAddRGBStop(pat, bg_shadow, 0.0, 0.22); + PatternAddRGBStop(pat, bg_shadow, 1.0, 0.1); + break; + default: + break; + } + + cairo_set_source(cr, pat); + cairo_pattern_destroy(pat); + + cairoGraphics->DrawRoundedRectangle(cr, 1.0f, 1.0, 1.0, radius, width- 2, height - 2); + cairo_stroke(cr); + + nux::Color bg_dark_line = ProduceColorShade(bg, 0.4); + nux::Color bg_bright_line = ProduceColorShade(bg, 1.2); + + cairoGraphics->DrawRoundedRectangle(cr, 1.0f, 2.0, 2.0, radius - 1, width - 4, height- 4); + SetSourceRGB(cr, bg_bright_line, 0.6); + cairo_stroke(cr); + + DrawBothGrips(cr, bg_dark_line, width, height); + DrawLineSeperator(cr, bg_dark_line, bg_bright_line, width, height); + DrawBothArrows(cr, width, height); + + if (thumb_texture_) + thumb_texture_->UnReference(); + thumb_texture_ = unity::texture_from_cairo_graphics(*cairoGraphics); + + cairo_destroy(cr); + delete cairoGraphics; + + QueueDraw(); +} diff --git a/unity-shared/VScrollBarOverlayWindow.h b/unity-shared/VScrollBarOverlayWindow.h new file mode 100644 index 000000000..344a60e53 --- /dev/null +++ b/unity-shared/VScrollBarOverlayWindow.h @@ -0,0 +1,91 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2012 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Authored by: Brandon Schaefer <brandon.schaefer@canonical.com> + */ + +#include <Nux/Nux.h> +#include <Nux/BaseWindow.h> + +#include "unity-shared/UBusWrapper.h" + + +class VScrollBarOverlayWindow : public nux::BaseWindow +{ +public: + VScrollBarOverlayWindow(const nux::Geometry geo); + ~VScrollBarOverlayWindow(); + + void UpdateGeometry(const nux::Geometry& geo); + void SetThumbOffsetY(int y); + + void MouseDown(); + void MouseUp(); + + void MouseNear(); + void MouseBeyond(); + + void ThumbInsideSlider(); + void ThumbOutsideSlider(); + + void PageUpAction(); + void PageDownAction(); + + bool IsMouseInsideThumb(int x, int y) const; + bool IsMouseBeingDragged() const; + + int GetThumbHeight() const; + int GetThumbOffsetY() const; + + nux::Geometry GetThumbGeometry() const; + + virtual void DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw); + +private: + enum class ThumbAction : unsigned int + { + NONE, + DRAGGING, + PAGE_UP, + PAGE_DOWN + }; + + void MouseDragging(); + void UpdateMouseOffsetX(); + int GetValidOffsetYValue(int y) const; + + void ShouldShow(); + void ShouldHide(); + + void ResetStates(); + void UpdateTexture(); + + void OnOverlayHidden(GVariant* data); + + unity::UBusManager _ubus_manager; + nux::Geometry content_size_; + + nux::ObjectPtr<nux::BaseTexture> thumb_texture_; + + int content_offset_x_; + int mouse_offset_y_; + + bool mouse_down_; + bool mouse_near_; + bool inside_slider_; + + ThumbAction current_action_; +}; |
