You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
323 lines
12 KiB
323 lines
12 KiB
#include "ToolbarAdapter.h" |
|
|
|
#include <utility> |
|
|
|
#include "control/Control.h" |
|
#include "gui/ToolitemDragDrop.h" |
|
#include "gui/toolbarMenubar/AbstractToolItem.h" |
|
#include "gui/toolbarMenubar/ColorToolItem.h" |
|
#include "gui/toolbarMenubar/icon/ColorSelectImage.h" |
|
#include "gui/toolbarMenubar/model/ToolbarData.h" |
|
|
|
#include "ToolItemDragCurrentData.h" |
|
#include "ToolbarDragDropHelper.h" |
|
#include "Util.h" |
|
#include "i18n.h" |
|
|
|
ToolbarAdapter::ToolbarAdapter(GtkWidget* toolbar, string toolbarName, ToolMenuHandler* toolHandler, |
|
MainWindow* window) { |
|
this->w = toolbar; |
|
this->toolbarName = std::move(toolbarName); |
|
this->toolHandler = toolHandler; |
|
this->window = window; |
|
|
|
// prepare drag & drop |
|
gtk_drag_dest_set(toolbar, GTK_DEST_DEFAULT_ALL, nullptr, 0, GDK_ACTION_MOVE); |
|
ToolbarDragDropHelper::dragDestAddToolbar(toolbar); |
|
|
|
g_signal_connect(toolbar, "drag_motion", G_CALLBACK(toolbarDragMotionCb), this); |
|
g_signal_connect(toolbar, "drag_leave", G_CALLBACK(toolbarDragLeafeCb), this); |
|
g_signal_connect(toolbar, "drag_data_received", G_CALLBACK(toolbarDragDataReceivedCb), this); |
|
|
|
showToolbar(); |
|
prepareToolItems(); |
|
} |
|
|
|
ToolbarAdapter::~ToolbarAdapter() { |
|
// remove drag & drop handler |
|
g_signal_handlers_disconnect_by_func(this->w, (gpointer)toolbarDragMotionCb, this); |
|
g_signal_handlers_disconnect_by_func(this->w, (gpointer)toolbarDragLeafeCb, this); |
|
g_signal_handlers_disconnect_by_func(this->w, (gpointer)toolbarDragDataReceivedCb, this); |
|
|
|
cleanupToolbars(); |
|
} |
|
|
|
void ToolbarAdapter::cleanupToolbars() { |
|
GtkWidget* w = GTK_WIDGET(this->spacerItem); |
|
GtkWidget* parent = gtk_widget_get_parent(w); |
|
gtk_container_remove(GTK_CONTAINER(parent), w); |
|
|
|
GtkToolbar* tb = GTK_TOOLBAR(this->w); |
|
if (gtk_toolbar_get_n_items(tb) == 0) { |
|
gtk_widget_hide(this->w); |
|
} else { |
|
for (int i = 0; i < gtk_toolbar_get_n_items(tb); i++) { |
|
GtkToolItem* it = gtk_toolbar_get_nth_item(tb, i); |
|
cleanToolItem(it); |
|
} |
|
} |
|
} |
|
|
|
void ToolbarAdapter::prepareToolItems() { |
|
GtkToolbar* tb = GTK_TOOLBAR(this->w); |
|
|
|
for (int i = 0; i < gtk_toolbar_get_n_items(tb); i++) { |
|
GtkToolItem* it = gtk_toolbar_get_nth_item(tb, i); |
|
prepareToolItem(it); |
|
} |
|
} |
|
|
|
void ToolbarAdapter::cleanToolItem(GtkToolItem* it) { |
|
ToolItemDragDropData* data = ToolitemDragDrop::metadataGetMetadata(GTK_WIDGET(it)); |
|
if (data) { |
|
gtk_widget_set_sensitive(GTK_WIDGET(it), ToolitemDragDrop::isToolItemEnabled(data)); |
|
} |
|
|
|
gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(it)), nullptr); |
|
|
|
gtk_tool_item_set_use_drag_window(it, false); |
|
gtk_drag_source_unset(GTK_WIDGET(it)); |
|
|
|
g_signal_handlers_disconnect_by_func(it, (gpointer)toolitemDragBegin, nullptr); |
|
g_signal_handlers_disconnect_by_func(it, (gpointer)toolitemDragEnd, nullptr); |
|
g_signal_handlers_disconnect_by_func(it, (gpointer)toolitemDragDataGet, this); |
|
} |
|
|
|
void ToolbarAdapter::prepareToolItem(GtkToolItem* it) { |
|
// if disable drag an drop is not possible |
|
gtk_widget_set_sensitive(GTK_WIDGET(it), true); |
|
|
|
gtk_tool_item_set_use_drag_window(it, true); |
|
|
|
GdkScreen* screen = gtk_widget_get_screen(GTK_WIDGET(it)); |
|
GdkCursor* cursor = gdk_cursor_new_for_display(gdk_screen_get_display(screen), GDK_HAND2); |
|
gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(it)), cursor); |
|
g_object_unref(cursor); |
|
|
|
gtk_drag_source_set(GTK_WIDGET(it), GDK_BUTTON1_MASK, &ToolbarDragDropHelper::dropTargetEntry, 1, GDK_ACTION_MOVE); |
|
ToolbarDragDropHelper::dragSourceAddToolbar(GTK_WIDGET(it)); |
|
|
|
g_signal_connect(it, "drag-begin", G_CALLBACK(toolitemDragBegin), nullptr); |
|
g_signal_connect(it, "drag-end", G_CALLBACK(toolitemDragEnd), nullptr); |
|
g_signal_connect(it, "drag-data-get", G_CALLBACK(toolitemDragDataGet), this); |
|
} |
|
|
|
void ToolbarAdapter::showToolbar() { |
|
gtk_widget_show(this->w); |
|
|
|
GtkToolbar* tb = GTK_TOOLBAR(this->w); |
|
|
|
GtkToolItem* it = gtk_tool_item_new(); |
|
this->spacerItem = it; |
|
gtk_toolbar_insert(tb, it, 0); |
|
|
|
GtkOrientation orientation = gtk_orientable_get_orientation(GTK_ORIENTABLE(tb)); |
|
if (orientation == GTK_ORIENTATION_HORIZONTAL) { |
|
gtk_widget_set_size_request(GTK_WIDGET(it), 0, 20); |
|
} else if (orientation == GTK_ORIENTATION_VERTICAL) { |
|
gtk_widget_set_size_request(GTK_WIDGET(it), 20, 0); |
|
} |
|
} |
|
|
|
/** |
|
* Drag a Toolitem from toolbar |
|
*/ |
|
void ToolbarAdapter::toolitemDragBegin(GtkWidget* widget, GdkDragContext* context, void* unused) { |
|
ToolItemDragDropData* data = ToolitemDragDrop::metadataGetMetadata(widget); |
|
|
|
g_return_if_fail(data != nullptr); |
|
|
|
ToolItemDragCurrentData::setData(data); |
|
|
|
GtkWidget* icon = ToolitemDragDrop::getIcon(data); |
|
|
|
gtk_drag_set_icon_pixbuf(context, ToolbarDragDropHelper::getImagePixbuf(GTK_IMAGE(icon)), -2, -2); |
|
|
|
g_object_unref(icon); |
|
|
|
gtk_widget_hide(widget); |
|
} |
|
|
|
/** |
|
* Drag a Toolitem from toolbar STOPPED |
|
*/ |
|
void ToolbarAdapter::toolitemDragEnd(GtkWidget* widget, GdkDragContext* context, void* unused) { |
|
ToolItemDragCurrentData::clearData(); |
|
gtk_widget_show(widget); |
|
} |
|
|
|
/** |
|
* Remove a toolbar item from the tool where it was |
|
*/ |
|
void ToolbarAdapter::removeFromToolbar(AbstractToolItem* item, const string& toolbarName, int id) { |
|
ToolbarData* d = this->window->getSelectedToolbar(); |
|
if (d->removeItemByID(toolbarName, id)) { |
|
if (item != nullptr) { |
|
g_message( |
|
"%s", |
|
FS(_F("Removed tool item {1} from Toolbar {2} ID {3}") % item->getId() % toolbarName % id).c_str()); |
|
} else { |
|
g_message("%s", FS(_F("Removed tool item from Toolbar {1} ID {2}") % toolbarName % id).c_str()); |
|
} |
|
} else { |
|
if (item != nullptr) { |
|
g_message("%s", FS(_F("Could not remove tool item {1} from Toolbar {2} on position {3}") % item->getId() % |
|
toolbarName % id) |
|
.c_str()); |
|
} else { |
|
g_message("%s", |
|
FS(_F("Could not remove tool item from Toolbar {1} on position {2}") % toolbarName % id).c_str()); |
|
} |
|
} |
|
} |
|
|
|
void ToolbarAdapter::toolitemDragDataGet(GtkWidget* widget, GdkDragContext* context, GtkSelectionData* selection_data, |
|
guint info, guint time, ToolbarAdapter* adapter) { |
|
ToolItemDragDropData* data = ToolitemDragDrop::metadataGetMetadata(widget); |
|
|
|
g_return_if_fail(data != nullptr); |
|
|
|
GtkToolbar* tb = GTK_TOOLBAR(adapter->w); |
|
int position = -1; |
|
for (int i = 0; i < gtk_toolbar_get_n_items(tb); i++) { |
|
GtkToolItem* it = gtk_toolbar_get_nth_item(tb, i); |
|
|
|
if (static_cast<void*>(it) == static_cast<void*>(widget)) { |
|
adapter->cleanToolItem(it); |
|
gtk_container_remove(GTK_CONTAINER(tb), GTK_WIDGET(it)); |
|
position = i; |
|
break; |
|
} |
|
} |
|
|
|
g_return_if_fail(position != -1); |
|
|
|
adapter->removeFromToolbar(data->item, adapter->toolbarName, data->id); |
|
|
|
gtk_selection_data_set(selection_data, ToolbarDragDropHelper::atomToolItem, 0, |
|
reinterpret_cast<const guchar*>(data), sizeof(ToolItemDragDropData)); |
|
} |
|
|
|
/** |
|
* A tool item was dragged to the toolbar |
|
*/ |
|
auto ToolbarAdapter::toolbarDragMotionCb(GtkToolbar* toolbar, GdkDragContext* context, gint x, gint y, guint time, |
|
ToolbarAdapter* adapter) -> bool { |
|
GdkAtom target = gtk_drag_dest_find_target(GTK_WIDGET(toolbar), context, nullptr); |
|
if (target != ToolbarDragDropHelper::atomToolItem) { |
|
gdk_drag_status(context, static_cast<GdkDragAction>(0), time); |
|
return false; |
|
} |
|
|
|
// x,y are already in toolbar coordinates as the gtk_toolbar_get_drop_index() specification requires. |
|
// However, without this translation we have an unwanted vertical offset. |
|
gint wx = 0; |
|
gint wy = 0; |
|
gtk_widget_translate_coordinates(GTK_WIDGET(toolbar), gtk_widget_get_toplevel(GTK_WIDGET(toolbar)), x, y, &wx, &wy); |
|
|
|
gint ipos = gtk_toolbar_get_drop_index(toolbar, wx, wy); |
|
|
|
GtkOrientation orientation = gtk_orientable_get_orientation(GTK_ORIENTABLE(toolbar)); |
|
gdk_drag_status(context, gdk_drag_context_get_suggested_action(context), time); |
|
|
|
ToolItemDragDropData* d = ToolItemDragCurrentData::getData(); |
|
|
|
if (d == nullptr) { |
|
g_warning("ToolbarAdapter.cpp, ToolItemDragDropData == nullptr"); |
|
return false; |
|
} |
|
|
|
if (d->type == TOOL_ITEM_ITEM) { |
|
gtk_toolbar_set_drop_highlight_item(toolbar, d->item->createTmpItem(orientation == GTK_ORIENTATION_HORIZONTAL), |
|
ipos); |
|
} else if (d->type == TOOL_ITEM_SEPARATOR) { |
|
GtkToolItem* it = gtk_separator_tool_item_new(); |
|
gtk_toolbar_set_drop_highlight_item(toolbar, it, ipos); |
|
} else if (d->type == TOOL_ITEM_COLOR) { |
|
GtkWidget* iconWidget = ColorSelectImage::newColorIcon(d->color, 16, true); |
|
GtkToolItem* it = gtk_tool_button_new(iconWidget, ""); |
|
gtk_toolbar_set_drop_highlight_item(toolbar, it, ipos); |
|
} else { |
|
g_warning("ToolbarAdapter::toolbarDragMotionCb Unhandled type %i", d->type); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
void ToolbarAdapter::toolbarDragLeafeCb(GtkToolbar* toolbar, GdkDragContext* context, guint time, |
|
ToolbarAdapter* adapter) { |
|
gtk_toolbar_set_drop_highlight_item(toolbar, nullptr, -1); |
|
} |
|
|
|
void ToolbarAdapter::toolbarDragDataReceivedCb(GtkToolbar* toolbar, GdkDragContext* context, gint x, gint y, |
|
GtkSelectionData* data, guint info, guint time, |
|
ToolbarAdapter* adapter) { |
|
auto* d = reinterpret_cast<ToolItemDragDropData const*>(gtk_selection_data_get_data(data)); |
|
g_return_if_fail(ToolitemDragDrop::checkToolItemDragDropData(d)); |
|
|
|
// fix vertical position bug as in toolbarDragMotionCb() above. |
|
gint wx = 0; |
|
gint wy = 0; |
|
gtk_widget_translate_coordinates(GTK_WIDGET(toolbar), gtk_widget_get_toplevel(GTK_WIDGET(toolbar)), x, y, &wx, &wy); |
|
|
|
gint pos = gtk_toolbar_get_drop_index(toolbar, wx, wy); |
|
|
|
if (d->type == TOOL_ITEM_ITEM) { |
|
bool horizontal = gtk_orientable_get_orientation(GTK_ORIENTABLE(toolbar)) == GTK_ORIENTATION_HORIZONTAL; |
|
GtkToolItem* it = d->item->createItem(horizontal); |
|
|
|
adapter->prepareToolItem(it); |
|
|
|
gtk_widget_show_all(GTK_WIDGET(it)); |
|
gtk_toolbar_insert(toolbar, it, pos); |
|
|
|
ToolbarData* tb = adapter->window->getSelectedToolbar(); |
|
const char* name = adapter->window->getToolbarName(toolbar); |
|
|
|
string id = d->item->getId(); |
|
|
|
int newId = tb->insertItem(name, id, pos); |
|
ToolitemDragDrop::attachMetadata(GTK_WIDGET(it), newId, d->item); |
|
} else if (d->type == TOOL_ITEM_COLOR) { |
|
// [idotobi]: TODO fix |
|
auto palette = adapter->window->getControl()->getSettings()->palette; |
|
auto namedColor = palette->getNext(); |
|
auto c = Util::colorU16_to_rgb(namedColor.color); |
|
auto colorName = namedColor.name; |
|
|
|
auto* item = new ColorToolItem(adapter->window->getControl(), adapter->window->getControl()->getToolHandler(), |
|
GTK_WINDOW(adapter->window->getWindow()), c, colorName); |
|
|
|
bool horizontal = gtk_orientable_get_orientation(GTK_ORIENTABLE(toolbar)) == GTK_ORIENTATION_HORIZONTAL; |
|
GtkToolItem* it = item->createItem(horizontal); |
|
|
|
adapter->prepareToolItem(it); |
|
|
|
gtk_widget_show_all(GTK_WIDGET(it)); |
|
gtk_toolbar_insert(toolbar, it, pos); |
|
|
|
ToolbarData* tb = adapter->window->getSelectedToolbar(); |
|
const char* name = adapter->window->getToolbarName(toolbar); |
|
|
|
string id = item->getId(); |
|
|
|
int newId = tb->insertItem(name, id, pos); |
|
ToolitemDragDrop::attachMetadataColor(GTK_WIDGET(it), newId, d->color, item); |
|
|
|
adapter->window->getToolMenuHandler()->addColorToolItem(item); |
|
} else if (d->type == TOOL_ITEM_SEPARATOR) { |
|
GtkToolItem* it = gtk_separator_tool_item_new(); |
|
gtk_widget_show_all(GTK_WIDGET(it)); |
|
gtk_toolbar_insert(toolbar, it, pos); |
|
|
|
adapter->prepareToolItem(it); |
|
|
|
ToolbarData* tb = adapter->window->getSelectedToolbar(); |
|
const char* name = adapter->window->getToolbarName(toolbar); |
|
|
|
int newId = tb->insertItem(name, "SEPARATOR", pos); |
|
ToolitemDragDrop::attachMetadata(GTK_WIDGET(it), newId, TOOL_ITEM_SEPARATOR); |
|
} else { |
|
g_warning("toolbarDragDataReceivedCb: ToolItemType %i not handled!", d->type); |
|
} |
|
}
|
|
|