1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
15 #include "gtv-calc-header-bar.hxx"
17 #include <boost/property_tree/ptree.hpp>
18 #include <o3tl/unreachable.hxx>
22 struct GtvCalcHeaderBarPrivateImpl
24 /// Stores size and content of a single row header.
29 Header(int nSize
, const std::string
& rText
)
35 std::vector
<Header
> m_aHeaders
;
36 CalcHeaderType m_eType
;
38 GtvCalcHeaderBarPrivateImpl()
39 : m_eType(CalcHeaderType::NONE
)
43 struct GtvCalcHeaderBarPrivate
45 GtvCalcHeaderBarPrivateImpl
* m_pImpl
;
47 GtvCalcHeaderBarPrivateImpl
* operator->()
56 #if __has_warning("-Wdeprecated-volatile")
57 #pragma clang diagnostic push
58 #pragma clang diagnostic ignored "-Wdeprecated-volatile"
61 G_DEFINE_TYPE_WITH_PRIVATE(GtvCalcHeaderBar
, gtv_calc_header_bar
, GTK_TYPE_DRAWING_AREA
);
63 #if __has_warning("-Wdeprecated-volatile")
64 #pragma clang diagnostic pop
68 const int ROW_HEADER_WIDTH
= 50;
69 const int COLUMN_HEADER_HEIGHT
= 20;
71 static GtvCalcHeaderBarPrivate
&
72 getPrivate(GtvCalcHeaderBar
* headerbar
)
74 return *static_cast<GtvCalcHeaderBarPrivate
*>(gtv_calc_header_bar_get_instance_private(headerbar
));
78 gtv_calc_header_bar_init(GtvCalcHeaderBar
* bar
)
80 GtvCalcHeaderBarPrivate
& priv
= getPrivate(bar
);
81 priv
.m_pImpl
= new GtvCalcHeaderBarPrivateImpl();
85 gtv_calc_header_bar_finalize(GObject
* object
)
87 GtvCalcHeaderBarPrivate
& priv
= getPrivate(GTV_CALC_HEADER_BAR(object
));
90 priv
.m_pImpl
= nullptr;
92 G_OBJECT_CLASS (gtv_calc_header_bar_parent_class
)->finalize (object
);
95 static void gtv_calc_header_bar_draw_text(cairo_t
* pCairo
, const GdkRectangle
& rRectangle
, const std::string
& rText
)
97 cairo_text_extents_t extents
;
98 cairo_text_extents(pCairo
, rText
.c_str(), &extents
);
99 // Cairo reference point for text is the bottom left corner.
100 cairo_move_to(pCairo
, rRectangle
.x
+ rRectangle
.width
/ 2 - extents
.width
/ 2, rRectangle
.y
+ rRectangle
.height
/ 2 + extents
.height
/ 2);
101 cairo_show_text(pCairo
, rText
.c_str());
104 static bool gtv_calc_header_bar_draw_impl(GtkWidget
* pWidget
, cairo_t
* pCairo
)
106 GtvCalcHeaderBar
* self
= GTV_CALC_HEADER_BAR(pWidget
);
107 GtvCalcHeaderBarPrivate
& priv
= getPrivate(GTV_CALC_HEADER_BAR(self
));
108 cairo_set_source_rgb(pCairo
, 0, 0, 0);
111 for (const GtvCalcHeaderBarPrivateImpl::Header
& rHeader
: priv
->m_aHeaders
)
113 GdkRectangle aRectangle
;
114 if (priv
->m_eType
== CalcHeaderType::ROW
)
117 aRectangle
.y
= nPrevious
;
118 aRectangle
.width
= ROW_HEADER_WIDTH
- 1;
119 aRectangle
.height
= rHeader
.m_nSize
- nPrevious
;
121 cairo_rectangle(pCairo
, aRectangle
.x
, aRectangle
.y
, 1, aRectangle
.height
);
124 cairo_rectangle(pCairo
, aRectangle
.x
, aRectangle
.y
+ aRectangle
.height
, aRectangle
.width
, 1);
127 cairo_rectangle(pCairo
, aRectangle
.width
, aRectangle
.y
, 1, aRectangle
.height
);
130 else if (priv
->m_eType
== CalcHeaderType::COLUMN
)
132 aRectangle
.x
= nPrevious
;
134 aRectangle
.width
= rHeader
.m_nSize
- nPrevious
;
135 aRectangle
.height
= COLUMN_HEADER_HEIGHT
- 1;
137 cairo_rectangle(pCairo
, aRectangle
.x
, aRectangle
.y
, aRectangle
.width
, 1);
140 cairo_rectangle(pCairo
, aRectangle
.x
+ aRectangle
.width
, aRectangle
.y
, 1, aRectangle
.height
);
143 cairo_rectangle(pCairo
, aRectangle
.x
, aRectangle
.height
, aRectangle
.width
, 1);
148 O3TL_UNREACHABLE
; // should never happen
151 gtv_calc_header_bar_draw_text(pCairo
, aRectangle
, rHeader
.m_aText
);
152 nPrevious
= rHeader
.m_nSize
;
153 if (rHeader
.m_nSize
> self
->m_nSizePixel
)
157 if (priv
->m_aHeaders
.empty() && priv
->m_eType
== CalcHeaderType::CORNER
)
159 GdkRectangle aRectangle
;
162 aRectangle
.width
= ROW_HEADER_WIDTH
- 1;
163 aRectangle
.height
= COLUMN_HEADER_HEIGHT
- 1;
164 cairo_rectangle(pCairo
, aRectangle
.x
, aRectangle
.y
, aRectangle
.width
, aRectangle
.height
);
165 cairo_stroke(pCairo
);
172 gtv_calc_header_bar_draw(GtkWidget
* bar
, cairo_t
* pCairo
)
174 return gtv_calc_header_bar_draw_impl(bar
, pCairo
);
178 gtv_calc_header_bar_class_init(GtvCalcHeaderBarClass
* klass
)
180 GTK_WIDGET_CLASS(klass
)->draw
= gtv_calc_header_bar_draw
;
181 G_OBJECT_CLASS(klass
)->finalize
= gtv_calc_header_bar_finalize
;
184 void gtv_calc_header_bar_configure(GtvCalcHeaderBar
* bar
, const boost::property_tree::ptree
* values
)
186 GtvCalcHeaderBarPrivate
& priv
= getPrivate(bar
);
187 priv
->m_aHeaders
.clear();
191 boost::property_tree::ptree val
= *values
;
194 for (const boost::property_tree::ptree::value_type
& rValue
: val
)
196 int nSize
= std::round(std::atof(rValue
.second
.get
<std::string
>("size").c_str()));
197 if (nSize
>= bar
->m_nPositionPixel
)
199 const int nScrolledSize
= nSize
- bar
->m_nPositionPixel
;
200 GtvCalcHeaderBarPrivateImpl::Header
aHeader(nScrolledSize
, rValue
.second
.get
<std::string
>("text"));
201 priv
->m_aHeaders
.push_back(aHeader
);
205 catch (boost::property_tree::ptree_bad_path
& rException
)
207 std::cerr
<< "gtv_calc_header_bar_configure: " << rException
.what() << std::endl
;
210 gtk_widget_show(GTK_WIDGET(bar
));
211 gtk_widget_queue_draw(GTK_WIDGET(bar
));
215 gtv_calc_header_bar_set_type_and_width(GtvCalcHeaderBar
* bar
, CalcHeaderType eType
)
217 // TODO: Install type property for this class
218 GtvCalcHeaderBarPrivate
& priv
= getPrivate(bar
);
219 priv
->m_eType
= eType
;
221 if (eType
== CalcHeaderType::ROW
)
222 gtk_widget_set_size_request(GTK_WIDGET(bar
), ROW_HEADER_WIDTH
, -1);
223 else if (eType
== CalcHeaderType::COLUMN
)
224 gtk_widget_set_size_request(GTK_WIDGET(bar
), -1, COLUMN_HEADER_HEIGHT
);
228 gtv_calc_header_bar_new()
230 return GTK_WIDGET(g_object_new(GTV_TYPE_CALC_HEADER_BAR
,
234 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */