#include "FloatingToolbox.h" #include #include "control/Control.h" #include "control/settings/ButtonConfig.h" #include "gui/ToolbarDefinitions.h" #include "GladeGui.h" #include "MainWindow.h" FloatingToolbox::FloatingToolbox(MainWindow* theMainWindow, GtkOverlay* overlay) { this->mainWindow = theMainWindow; this->floatingToolbox = theMainWindow->get("floatingToolbox"); this->floatingToolboxX = 200; this->floatingToolboxY = 200; this->floatingToolboxState = recalcSize; gtk_overlay_add_overlay(overlay, this->floatingToolbox); gtk_overlay_set_overlay_pass_through(overlay, this->floatingToolbox, true); gtk_widget_add_events(this->floatingToolbox, GDK_LEAVE_NOTIFY_MASK); g_signal_connect(this->floatingToolbox, "leave-notify-event", G_CALLBACK(handleLeaveFloatingToolbox), this); // position overlay widgets g_signal_connect(overlay, "get-child-position", G_CALLBACK(this->getOverlayPosition), this); } FloatingToolbox::~FloatingToolbox() = default; void FloatingToolbox::show(int x, int y) { this->floatingToolboxX = x; this->floatingToolboxY = y; this->show(); } /**** * floatingToolboxActivated * True if the user has: * assigned a mouse or stylus button to bring up the floatingToolbox; * or enabled tapAction and Show FloatingToolbox( prefs->DrawingArea->ActionOnToolTap ); * or put tools in the FloatingToolbox. * */ auto FloatingToolbox::floatingToolboxActivated() -> bool { Settings* settings = this->mainWindow->getControl()->getSettings(); ButtonConfig* cfg = nullptr; // check if any buttons assigned to bring up toolbox for (int id = 0; id < BUTTON_COUNT; id++) { cfg = settings->getButtonConfig(id); if (cfg->getAction() == TOOL_FLOATING_TOOLBOX) { return true; // return true } } // check if user can show Floating Menu with tap. if (settings->getDoActionOnStrokeFiltered() && settings->getStrokeFilterEnabled()) { return true; // return true } if (this->countWidgets() > 0) // FloatingToolbox contains something { return true; // return true } return false; } auto FloatingToolbox::countWidgets() -> int { int count = 0; for (int index = TBFloatFirst; index <= TBFloatLast; index++) { const char* guiName = TOOLBAR_DEFINITIONS[index].guiName; GtkToolbar* toolbar1 = GTK_TOOLBAR(this->mainWindow->get(guiName)); count += gtk_toolbar_get_n_items(toolbar1); } return count; } void FloatingToolbox::showForConfiguration() { if (this->floatingToolboxActivated()) // Do not show if not being used - at least while experimental. { GtkWidget* boxContents = this->mainWindow->get("boxContents"); gint wx = 0, wy = 0; gtk_widget_translate_coordinates(boxContents, gtk_widget_get_toplevel(boxContents), 0, 0, &wx, &wy); this->floatingToolboxX = wx + 40; // when configuration state these are this->floatingToolboxY = wy + 40; // topleft coordinates( otherwise center). this->floatingToolboxState = configuration; this->show(); } } void FloatingToolbox::show() { gtk_widget_hide(this->floatingToolbox); // force showing in new position gtk_widget_show_all(this->floatingToolbox); if (this->floatingToolboxState != configuration) { gtk_widget_hide(this->mainWindow->get("labelFloatingToolbox")); } if (this->floatingToolboxState == configuration || countWidgets() > 0) { gtk_widget_hide(this->mainWindow->get("showIfEmpty")); } } void FloatingToolbox::hide() { if (this->floatingToolboxState == configuration) { this->floatingToolboxState = recalcSize; } gtk_widget_hide(this->floatingToolbox); } void FloatingToolbox::flagRecalculateSizeRequired() { this->floatingToolboxState = recalcSize; } /** * getOverlayPosition - this is how we position the widget in the overlay under the mouse * * The requested location is communicated via the FloatingToolbox member variables: * ->floatingToolbox, so we can operate on the right widget * ->floatingToolboxState, are we configuring, resizing or just moving * ->floatingToolboxX, where to display * ->floatingToolboxY. * */ auto FloatingToolbox::getOverlayPosition(GtkOverlay* overlay, GtkWidget* widget, GdkRectangle* allocation, FloatingToolbox* self) -> gboolean { if (widget == self->floatingToolbox) { gtk_widget_get_allocation(widget, allocation); // get existing width and height if (self->floatingToolboxState != noChange || allocation->height < 2) // if recalcSize or configuration or initiation. { GtkRequisition natural; gtk_widget_get_preferred_size(widget, nullptr, &natural); allocation->width = natural.width; allocation->height = natural.height; } switch (self->floatingToolboxState) { case recalcSize: // fallthrough note: recalc done above case noChange: // show centered on x,y allocation->x = self->floatingToolboxX - allocation->width / 2; allocation->y = self->floatingToolboxY - allocation->height / 2; self->floatingToolboxState = noChange; break; case configuration: allocation->x = self->floatingToolboxX; allocation->y = self->floatingToolboxY; allocation->width = std::max(allocation->width + 32, 50); // always room for one more... allocation->height = std::max(allocation->height, 50); break; } return true; } return false; } void FloatingToolbox::handleLeaveFloatingToolbox(GtkWidget* floatingToolbox, GdkEvent* event, FloatingToolbox* self) { if (floatingToolbox == self->floatingToolbox) { if (self->floatingToolboxState != configuration) { self->hide(); } } }