From 8497298d730b9a24ad783f76bef76ca7c58b78e3 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Tue, 26 Jan 2021 22:39:04 +0100 Subject: [PATCH] Custom themable frame container As opposed to Gtk::Frame, this allows the background color of the content, inside the frame to be set and follows Ardour theme options. --- libs/widgets/frame.cc | 358 +++++++++++++++++++++++++++++++++++ libs/widgets/widgets/frame.h | 81 ++++++++ libs/widgets/wscript | 1 + 3 files changed, 440 insertions(+) create mode 100644 libs/widgets/frame.cc create mode 100644 libs/widgets/widgets/frame.h diff --git a/libs/widgets/frame.cc b/libs/widgets/frame.cc new file mode 100644 index 0000000000..6b815510fc --- /dev/null +++ b/libs/widgets/frame.cc @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2020 Robin Gareus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include "gtkmm2ext/colors.h" +#include "gtkmm2ext/utils.h" + +#include "widgets/frame.h" +#include "widgets/ui_config.h" + +using namespace std; +using namespace Gtk; +using namespace ArdourWidgets; + +Frame::Frame (Orientation orientation, bool boxy) + : _orientation (orientation) + , _w (0) + , _current_parent (0) + , _border (0) + , _padding (4) + , _label_pad_w (5) + , _label_pad_h (2) + , _label_left (12) + , _text_width (0) + , _text_height (0) + , _alloc_x0 (0) + , _alloc_y0 (0) + , _boxy (boxy) +{ + set_name ("Frame"); + ensure_style (); + _min_size.width = _min_size.height = 0; + _layout = Pango::Layout::create (get_pango_context ()); + + /* provide bg color for cairo child widgets */ + g_object_set_data (G_OBJECT (gobj ()), "has_cairo_widget_background_info", (void*)0xfeedface); + UIConfigurationBase::instance().DPIReset.connect (sigc::mem_fun (*this, &Frame::on_name_changed)); +} + +Frame::~Frame () +{ + if (_parent_style_change) { + _parent_style_change.disconnect (); + } + if (_w) { + _w->unparent (); + } +} + +void +Frame::on_add (Widget* w) +{ + if (_w || !w) { + return; + } + + Bin::on_add (w); + _w = w; + queue_resize (); +} + +void +Frame::on_remove (Gtk::Widget* w) +{ + Bin::on_remove (w); + assert (_w == w); + _w = 0; +} + +void +Frame::on_size_request (GtkRequisition* r) +{ + Bin::on_size_request (r); + _border = get_border_width (); + + _layout->set_markup (_label_text); + if (!_layout->get_text ().empty ()) { + _layout->get_pixel_size (_text_width, _text_height); + } else { + _text_width = _text_height = 0; + } + + if (_w) { + _w->size_request (*r); + } else { + r->width = 0; + r->height = 0; + } + + if (_text_width > 0) { + if (_orientation == Horizontal) { + r->width = max (r->width, _text_width + _label_pad_w * 2 + _label_left); + r->width += 2 * (_padding + _border); + r->height += 2 * (_padding + _border + _label_pad_h) + _text_height; + } else { + r->height = max (r->height, _text_width + _label_pad_w * 2 + _label_left); + r->width += 2 * (_padding + _border + _label_pad_h) + _text_height; + r->height += 2 * (_padding + _border); + } + } else { + r->height += 2 * (_padding + _border); + r->width += 2 * (_padding + _border); + } + _min_size = *r; +} + +void +Frame::on_size_allocate (Allocation& alloc) +{ + Bin::on_size_allocate (alloc); + _alloc_x0 = alloc.get_x (); + _alloc_y0 = alloc.get_y (); + + Allocation child_alloc; + if (alloc.get_width () < _min_size.width || alloc.get_height () < _min_size.height) { +#if 0 + printf ("Frame::on_size_allocate %dx%d < %dx%d\n", alloc.get_width (), alloc.get_height (), _min_size.width, _min_size.height); +#endif + return; + } + + int pb_l, pb_t; + if (_orientation == Horizontal) { + pb_l = _padding + _border; + pb_t = _padding + _border + (_text_width > 0 ? _label_pad_h : 0); + + child_alloc.set_x (alloc.get_x () + pb_l); + child_alloc.set_y (alloc.get_y () + pb_t + _text_height); + child_alloc.set_width (alloc.get_width () - pb_l * 2); + child_alloc.set_height (alloc.get_height () - pb_t * 2 - _text_height); + } else { + pb_l = _padding + _border + (_text_width > 0 ? _label_pad_h : 0);; + pb_t = _padding + _border; + + child_alloc.set_x (alloc.get_x () + pb_l + _text_height); + child_alloc.set_y (alloc.get_y () + pb_t); + child_alloc.set_width (alloc.get_width () - pb_l * 2 - _text_height); + child_alloc.set_height (alloc.get_height () - pb_t * 2); + } + + if (_w) { + _w->size_allocate (child_alloc); + } +} + +void +Frame::on_style_changed (const Glib::RefPtr& style) +{ + Bin::on_style_changed (style); + Glib::RefPtr const& new_style = get_style (); + if (_layout && (_layout->get_font_description ().gobj () == 0 || _layout->get_font_description () != new_style->get_font ())) { + _layout->set_font_description (new_style->get_font ()); + queue_resize (); + } else if (is_realized ()) { + queue_resize (); + } +} + +void +Frame::on_name_changed () +{ + ensure_style (); + queue_resize (); + queue_draw (); +} + +Glib::RefPtr