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/.
16 #include "gtv-calc-header-bar.hxx"
18 #include <boost/property_tree/ptree.hpp>
19 #include <o3tl/unreachable.hxx>
24 struct GtvCalcHeaderBarPrivateImpl
26 /// Stores size and content of a single row header.
31 Header(int nSize
, std::string aText
)
33 m_aText(std::move(aText
))
37 std::vector
<Header
> m_aHeaders
;
38 CalcHeaderType m_eType
;
40 GtvCalcHeaderBarPrivateImpl()
41 : m_eType(CalcHeaderType::NONE
)
45 struct GtvCalcHeaderBarPrivate
47 GtvCalcHeaderBarPrivateImpl
* m_pImpl
;
49 GtvCalcHeaderBarPrivateImpl
* operator->()
58 #if __has_warning("-Wdeprecated-volatile")
59 #pragma clang diagnostic push
60 #pragma clang diagnostic ignored "-Wdeprecated-volatile"
63 G_DEFINE_TYPE_WITH_PRIVATE(GtvCalcHeaderBar
, gtv_calc_header_bar
, GTK_TYPE_DRAWING_AREA
);
65 #if __has_warning("-Wdeprecated-volatile")
66 #pragma clang diagnostic pop
70 const int ROW_HEADER_WIDTH
= 50;
71 const int COLUMN_HEADER_HEIGHT
= 20;
73 static GtvCalcHeaderBarPrivate
&
74 getPrivate(GtvCalcHeaderBar
* headerbar
)
76 return *static_cast<GtvCalcHeaderBarPrivate
*>(gtv_calc_header_bar_get_instance_private(headerbar
));
80 gtv_calc_header_bar_init(GtvCalcHeaderBar
* bar
)
82 GtvCalcHeaderBarPrivate
& priv
= getPrivate(bar
);
83 priv
.m_pImpl
= new GtvCalcHeaderBarPrivateImpl();
87 gtv_calc_header_bar_finalize(GObject
* object
)
89 GtvCalcHeaderBarPrivate
& priv
= getPrivate(GTV_CALC_HEADER_BAR(object
));
92 priv
.m_pImpl
= nullptr;
94 G_OBJECT_CLASS (gtv_calc_header_bar_parent_class
)->finalize (object
);
97 static void gtv_calc_header_bar_draw_text(cairo_t
* pCairo
, const GdkRectangle
& rRectangle
, const std::string
& rText
)
99 cairo_text_extents_t extents
;
100 cairo_text_extents(pCairo
, rText
.c_str(), &extents
);
101 // Cairo reference point for text is the bottom left corner.
102 cairo_move_to(pCairo
, rRectangle
.x
+ rRectangle
.width
/ 2 - extents
.width
/ 2, rRectangle
.y
+ rRectangle
.height
/ 2 + extents
.height
/ 2);
103 cairo_show_text(pCairo
, rText
.c_str());
106 static bool gtv_calc_header_bar_draw_impl(GtkWidget
* pWidget
, cairo_t
* pCairo
)
108 GtvCalcHeaderBar
* self
= GTV_CALC_HEADER_BAR(pWidget
);
109 GtvCalcHeaderBarPrivate
& priv
= getPrivate(GTV_CALC_HEADER_BAR(self
));
110 cairo_set_source_rgb(pCairo
, 0, 0, 0);
113 for (const GtvCalcHeaderBarPrivateImpl::Header
& rHeader
: priv
->m_aHeaders
)
115 GdkRectangle aRectangle
;
116 if (priv
->m_eType
== CalcHeaderType::ROW
)
119 aRectangle
.y
= nPrevious
;
120 aRectangle
.width
= ROW_HEADER_WIDTH
- 1;
121 aRectangle
.height
= rHeader
.m_nSize
- nPrevious
;
123 cairo_rectangle(pCairo
, aRectangle
.x
, aRectangle
.y
, 1, aRectangle
.height
);
126 cairo_rectangle(pCairo
, aRectangle
.x
, aRectangle
.y
+ aRectangle
.height
, aRectangle
.width
, 1);
129 cairo_rectangle(pCairo
, aRectangle
.width
, aRectangle
.y
, 1, aRectangle
.height
);
132 else if (priv
->m_eType
== CalcHeaderType::COLUMN
)
134 aRectangle
.x
= nPrevious
;
136 aRectangle
.width
= rHeader
.m_nSize
- nPrevious
;
137 aRectangle
.height
= COLUMN_HEADER_HEIGHT
- 1;
139 cairo_rectangle(pCairo
, aRectangle
.x
, aRectangle
.y
, aRectangle
.width
, 1);
142 cairo_rectangle(pCairo
, aRectangle
.x
+ aRectangle
.width
, aRectangle
.y
, 1, aRectangle
.height
);
145 cairo_rectangle(pCairo
, aRectangle
.x
, aRectangle
.height
, aRectangle
.width
, 1);
150 O3TL_UNREACHABLE
; // should never happen
153 gtv_calc_header_bar_draw_text(pCairo
, aRectangle
, rHeader
.m_aText
);
154 nPrevious
= rHeader
.m_nSize
;
155 if (rHeader
.m_nSize
> self
->m_nSizePixel
)
159 if (priv
->m_aHeaders
.empty() && priv
->m_eType
== CalcHeaderType::CORNER
)
161 GdkRectangle aRectangle
;
164 aRectangle
.width
= ROW_HEADER_WIDTH
- 1;
165 aRectangle
.height
= COLUMN_HEADER_HEIGHT
- 1;
166 cairo_rectangle(pCairo
, aRectangle
.x
, aRectangle
.y
, aRectangle
.width
, aRectangle
.height
);
167 cairo_stroke(pCairo
);
174 gtv_calc_header_bar_draw(GtkWidget
* bar
, cairo_t
* pCairo
)
176 return gtv_calc_header_bar_draw_impl(bar
, pCairo
);
180 gtv_calc_header_bar_class_init(GtvCalcHeaderBarClass
* klass
)
182 GTK_WIDGET_CLASS(klass
)->draw
= gtv_calc_header_bar_draw
;
183 G_OBJECT_CLASS(klass
)->finalize
= gtv_calc_header_bar_finalize
;
186 void gtv_calc_header_bar_configure(GtvCalcHeaderBar
* bar
, const boost::property_tree::ptree
* values
)
188 GtvCalcHeaderBarPrivate
& priv
= getPrivate(bar
);
189 priv
->m_aHeaders
.clear();
193 boost::property_tree::ptree val
= *values
;
196 for (const boost::property_tree::ptree::value_type
& rValue
: val
)
198 int nSize
= std::round(std::atof(rValue
.second
.get
<std::string
>("size").c_str()));
199 if (nSize
>= bar
->m_nPositionPixel
)
201 const int nScrolledSize
= nSize
- bar
->m_nPositionPixel
;
202 GtvCalcHeaderBarPrivateImpl::Header
aHeader(nScrolledSize
, rValue
.second
.get
<std::string
>("text"));
203 priv
->m_aHeaders
.push_back(aHeader
);
207 catch (boost::property_tree::ptree_bad_path
& rException
)
209 std::cerr
<< "gtv_calc_header_bar_configure: " << rException
.what() << std::endl
;
212 gtk_widget_show(GTK_WIDGET(bar
));
213 gtk_widget_queue_draw(GTK_WIDGET(bar
));
217 gtv_calc_header_bar_set_type_and_width(GtvCalcHeaderBar
* bar
, CalcHeaderType eType
)
219 // TODO: Install type property for this class
220 GtvCalcHeaderBarPrivate
& priv
= getPrivate(bar
);
221 priv
->m_eType
= eType
;
223 if (eType
== CalcHeaderType::ROW
)
224 gtk_widget_set_size_request(GTK_WIDGET(bar
), ROW_HEADER_WIDTH
, -1);
225 else if (eType
== CalcHeaderType::COLUMN
)
226 gtk_widget_set_size_request(GTK_WIDGET(bar
), -1, COLUMN_HEADER_HEIGHT
);
230 gtv_calc_header_bar_new()
232 return GTK_WIDGET(g_object_new(GTV_TYPE_CALC_HEADER_BAR
,
236 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */