interface.cpp revision d5ad05ac17abfd7d2eae333a8c1233971e1c1a8f
#define __SP_INTERFACE_C__
/** @file
* @brief Main UI stuff
*/
/* Authors:
* Lauris Kaplinski <lauris@kaplinski.com>
* Frank Felfe <innerspace@iname.com>
* bulia byak <buliabyak@users.sf.net>
*
* Copyright (C) 1999-2005 authors
* Copyright (C) 2001-2002 Ximian, Inc.
* Copyright (C) 2004 David Turner
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <glib.h>
#include "inkscape-private.h"
#include "preferences.h"
#include "path-prefix.h"
#include "shortcuts.h"
#include "document.h"
#include "desktop-handles.h"
#include "file.h"
#include "interface.h"
#include "desktop.h"
#include "ui/context-menu.h"
#include "selection.h"
#include "selection-chemistry.h"
#include "svg-view-widget.h"
#include "widgets/desktop-widget.h"
#include "sp-item-group.h"
#include "sp-text.h"
#include "sp-gradient-fns.h"
#include "sp-gradient.h"
#include "sp-flowtext.h"
#include "sp-namedview.h"
#include "helper/gnome-utils.h"
#include "dialogs/dialog-events.h"
#include "message-context.h"
#include "ui/uxmanager.h"
// Added for color drag-n-drop
#if ENABLE_LCMS
#include "lcms.h"
#endif // ENABLE_LCMS
#include "display/sp-canvas.h"
#include "color.h"
#include "svg/svg-color.h"
#include "desktop-style.h"
#include "style.h"
#include "event-context.h"
#include "gradient-drag.h"
#include "widgets/ege-paint-def.h"
// Include Mac OS X menu synchronization on native OSX build
#ifdef GDK_WINDOWING_QUARTZ
#include "ige-mac-menu.h"
#endif
/* Drag and Drop */
typedef enum {
static GtkTargetEntry ui_drop_target_entries [] = {
#endif // ENABLE_MAGIC_COLORS
};
static GtkTargetEntry *completeDropTargets = 0;
static int completeDropTargetsCount = 0;
static bool temporarily_block_actions = false;
#define ENTRIES_SIZE(n) sizeof(n)/sizeof(n[0])
static void sp_ui_import_one_file(char const *filename);
unsigned int sensitive,
void *data);
void *data);
{NULL},
NULL,
NULL, /* set_active */
sp_ui_menu_item_set_sensitive, /* set_sensitive */
NULL, /* set_shortcut */
sp_ui_menu_item_set_name /* set_name */
};
static const int MIN_ONSCREEN_DISTANCE = 50;
void
{
if (editable) {
win->signal_focus_in_event().connect(sigc::mem_fun(*desktop_widget, &SPDesktopWidget::onFocusInEvent));
if (prefs_geometry) {
if (w>0 && h>0) {
x = MIN(gdk_screen_width() - w, x);
y = MIN(gdk_screen_height() - h, y);
desktop->setWindowSize(w, h);
}
// Only restore xy for the first window so subsequent windows don't overlap exactly
// with first. (Maybe rule should be only restore xy if it's different from xy of
// other desktops?)
// Empirically it seems that active_desktop==this desktop only the first time a
// desktop is created.
}
}
if (maxed) {
}
if (full) {
win->fullscreen();
}
}
} else {
}
if ( completeDropTargets == 0 || completeDropTargetsCount == 0 )
{
while ( list ) {
int i = 0;
for ( i = 0; typesXX[i]; i++ ) {
}
}
for ( int i = 0; i < (int)nui_drop_target_entries; i++ ) {
}
int pos = nui_drop_target_entries;
pos++;
}
}
"drag_data_received",
NULL);
"drag_motion",
NULL);
"drag_leave",
NULL);
// needed because the first ACTIVATE_DESKTOP was sent when there was no window yet
}
void
{
if (!document) return;
}
/* TODO: not yet working */
/* To be re-enabled (by adding to menu) once it works. */
void
{
if (!document) return;
}
/**
* \param widget unused
*/
void
{
return;
}
return; // Shutdown operation has been canceled, so do nothing
}
// Shutdown can proceed; use the stored reference to the desktop here instead of the current SP_ACTIVE_DESKTOP,
// because the user might have changed the focus in the meantime (see bug #381357 on Launchpad)
dt->destroyWidget();
}
/**
* sp_ui_close_all
*
* This function is called to exit the program, and iterates through all
* open document view windows, attempting to close each in turn. If the
* view has unsaved information, the user will be prompted to save,
* discard, or cancel.
*
* Returns FALSE if the user cancels the close_all operation, TRUE
* otherwise.
*/
unsigned int
sp_ui_close_all(void)
{
/* Iterate through all the windows, destroying each in the order they
become active */
while (SP_ACTIVE_DESKTOP) {
/* The user canceled the operation, so end doing the close */
return FALSE;
}
// Shutdown can proceed; use the stored reference to the desktop here instead of the current SP_ACTIVE_DESKTOP,
// because the user might have changed the focus in the meantime (see bug #381357 on Launchpad)
dt->destroyWidget();
}
return TRUE;
}
/*
* Some day when the right-click menus are ready to start working
* smarter with the verbs, we'll need to change this NULL being
* sent to sp_action_perform to something useful, or set some kind
* of global "right-clicked position" variable for actions to
* investigate when they're called.
*/
static void
{
if (!temporarily_block_actions) {
}
}
static void
{
}
static void
{
}
static void
{
Inkscape::UI::View::View *view = static_cast<Inkscape::UI::View::View*> (g_object_get_data(G_OBJECT(object), "view"));
}
static void
{
Inkscape::UI::View::View *view = static_cast<Inkscape::UI::View::View*> (g_object_get_data(G_OBJECT(object), "view"));
}
/**
* sp_ui_menuitem_add_icon
*
* Creates and attaches a scaled icon to the given menu item.
*
*/
void
{
} // end of sp_ui_menu_add_icon
/**
* sp_ui_menu_append_item
*
*
*/
static GtkWidget *
{
if (stock) {
} else if (label) {
item = (with_mnemonic)
} else {
}
if (callback) {
}
}
return item;
} // end of sp_ui_menu_append_item()
/**
\brief a wrapper around gdk_keyval_name producing (when possible) characters, not names
*/
static gchar const *
{
/* TODO: Compare with the definition of gtk_accel_label_refetch in gtk/gtkaccellabel.c (or
simply use GtkAccelLabel as the TODO comment in sp_ui_shortcut_string suggests). */
else return n;
}
/**
* \param shortcut A GDK keyval OR'd with SP_SHORTCUT_blah_MASK values.
* \param c Points to a buffer at least 256 bytes long.
*/
void
{
/* TODO: This function shouldn't exist. Our callers should use GtkAccelLabel instead of
* a generic GtkLabel containing this string, and should call gtk_widget_add_accelerator.
* Will probably need to change sp_shortcut_invoke callers.
*
* The existing gtk_label_new_with_mnemonic call can be replaced with
* g_object_new(GTK_TYPE_ACCEL_LABEL, NULL) followed by
* gtk_label_set_text_with_mnemonic(lbl, str).
*/
static GtkAccelLabelClass const &accel_lbl_cls
};
gchar *p = c;
for (unsigned i = 0; i < G_N_ELEMENTS(modifier_tbl); ++i) {
&& (p < end))
{
modifier_tbl[i].name,
}
}
if (p < end) {
}
}
void
{
unsigned int shortcut;
gchar *s;
if (!action)
return;
if (shortcut) {
s = g_stpcpy(s, " (");
s = g_stpcpy(s, ")");
}
}
/**
* sp_ui_menu_append_item_from_verb
*
* Appends a custom menu UI from a verb.
*
*/
static GtkWidget *
sp_ui_menu_append_item_from_verb(GtkMenu *menu, Inkscape::Verb *verb, Inkscape::UI::View::View *view, bool radio = false, GSList *group = NULL)
{
} else {
unsigned int shortcut;
if (shortcut) {
gchar c[256];
if (radio) {
} else {
}
} else {
if (radio) {
} else {
item = gtk_image_menu_item_new ();
}
}
nr_active_object_add_listener((NRActiveObject *)action, (NRObjectEventVector *)&menu_item_event_vector, sizeof(SPActionEventVector), item);
}
}
}
return item;
} // end of sp_ui_menu_append_item_from_verb
{
prefPath = "/focus/";
prefPath = "/fullscreen/";
} else {
prefPath = "/window/";
}
return prefPath;
}
static void
{
Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
pref_path += "/state";
}
static gboolean
{
Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
pref_path += "/state";
g_signal_handlers_block_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data);
g_signal_handlers_unblock_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data);
return FALSE;
}
{
if ( gtk_check_menu_item_get_active(menuitem) ) {
Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view");
// note: this will change once more options are in the task set support:
}
}
/**
* \brief Callback function to update the status of the radio buttons in the View -> Display mode menu (Normal, No Filters, Outline)
*/
static gboolean
{
Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(widget), "view");
bool new_state = false;
} else {
g_warning("update_view_menu does not handle this verb");
}
if (new_state) { //only one of the radio buttons has to be activated; the others will automatically be deactivated
// When the GtkMenuItem version of the "activate" signal has been emitted by a GtkRadioMenuItem, there is a second
// emission as the most recently active item is toggled to inactive. This is dealt with before the original signal is handled.
// This emission however should not invoke any actions, hence we block it here:
temporarily_block_actions = true;
temporarily_block_actions = false;
}
}
return FALSE;
}
void
sp_ui_menu_append_check_item_from_verb(GtkMenu *menu, Inkscape::UI::View::View *view, gchar const *label, gchar const *tip, gchar const *pref,
{
gchar c[256];
{
}
{
GtkWidget *l = gtk_label_new(c);
}
} else {
}
#if 0
nr_active_object_add_listener((NRActiveObject *)action, (NRObjectEventVector *)&menu_item_event_vector, sizeof(SPActionEventVector), item);
}
#endif
g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) (action ? action->tip : tip));
}
static void
{
// dealing with the bizarre filename convention in Inkscape for now
}
static void
{
}
void
{
// Use this loop to iterate through a list of possible document locations.
if (dir) {
continue; // skip non-svg files
continue; // skip default.*.svg (i.e. default.svg and translations) - it's in the menu already
// how does "filepath" ever get freed?
"activate",
if (view) {
// set null tip for now; later use a description from the template file
}
}
}
}
// toss the dirname
}
}
void
{
//sp_ui_menu_append_check_item_from_verb(m, view, _("_Menu"), _("Show or hide the menu bar"), "menu",
// checkitem_toggled, checkitem_update, 0);
sp_ui_menu_append_check_item_from_verb(m, view, _("Commands Bar"), _("Show or hide the Commands bar (under the menu)"), "commands",
sp_ui_menu_append_check_item_from_verb(m, view, _("Snap Controls Bar"), _("Show or hide the snapping controls"), "snaptoolbox",
sp_ui_menu_append_check_item_from_verb(m, view, _("Tool Controls Bar"), _("Show or hide the Tool Controls bar"), "toppanel",
sp_ui_menu_append_check_item_from_verb(m, view, _("_Toolbox"), _("Show or hide the main toolbox (on the left)"), "toolbox",
sp_ui_menu_append_check_item_from_verb(m, view, _("_Palette"), _("Show or hide the color palette"), "panels",
sp_ui_menu_append_check_item_from_verb(m, view, _("_Statusbar"), _("Show or hide the statusbar (at the bottom of the window)"), "statusbar",
}
{
_("Default"), _("Default interface setup"),
_("Custom"), _("Set the custom task"),
_("Wide"), _("Setup for widescreen work."),
0, 0
};
int count = 0;
gint active = Inkscape::UI::UXManager::getInstance()->getDefaultTask( dynamic_cast<SPDesktop*>(view) );
{
{
}
g_signal_connect( G_OBJECT(item), "toggled", reinterpret_cast<GCallback>(taskToggled), GINT_TO_POINTER(count) );
g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), const_cast<gchar*>(strs[1]) );
gtk_widget_show( item );
}
}
/** @brief Observer that updates the recent list's max document count */
public:
{}
// hack: the recent menu doesn't repopulate after changing the limit, so we force it
}
private:
};
/** \brief This function turns XML into a menu
\param menus This is the XML that defines the menu
\param menu Menu to be added to
\param view The View that this menu is being built for
This function is realitively simple as it just goes through the XML
and parses the individual elements. In the case of a submenu, it
just calls itself recursively. Because it is only reasonable to have
a couple of submenus, it is unlikely this will go more than two or
three times.
In the case of an unrecognized verb, a menu item is made to identify
the verb that is missing, and display that. The menu item is also made
insensitive.
*/
void
{
continue;
}
}
}
} else {
}
} else {
gtk_widget_set_sensitive(item, false);
}
continue;
}
// This was spelt wrong in the original version
// and so this is for backward compatibility. It can
// probably be dropped after the 0.44 release.
continue;
}
continue;
}
// create recent files menu
// sort most recently used documents first to preserve previous behavior
g_signal_connect(G_OBJECT(recent_menu), "item-activated", G_CALLBACK(sp_recent_open), (gpointer) NULL);
// add filter to only open files added by Inkscape
// this will just sit and update the list's item count
continue;
}
continue;
}
continue;
}
}
}
/** \brief Build the main tool bar
\param view View to build the bar for
Currently the main tool bar is built as a dynamic XML menu using
\c sp_ui_build_dyn_menus. This function builds the bar, and then
pass it to get items attached to it.
*/
{
#ifdef GDK_WINDOWING_QUARTZ
#endif
#ifdef GDK_WINDOWING_QUARTZ
return NULL;
#else
return mbar;
#endif
}
}
}
{
GtkWidget *m;
m = gtk_menu_new();
/* Undo and Redo */
/* Separator */
/* Separator */
/* Item menu */
if (item) {
}
/* layer menu */
if (item) {
if (SP_IS_GROUP(item)) {
}
}
( dt->currentLayer() != dt->currentRoot() && SP_OBJECT_PARENT(dt->currentLayer()) != dt->currentRoot() ) ) {
/* Separator */
}
/* TRANSLATORS: #%s is the id of the group e.g. <g id="#g7">, not a number. */
gtk_widget_show(w);
gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
}
gtk_widget_show(w);
gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
}
}
return m;
}
/* Drag and Drop */
void
guint /*event_time*/,
gpointer /*user_data*/)
{
switch (info) {
case APP_X_INKY_COLOR:
{
int destX = 0;
int destY = 0;
if ( item )
{
gchar c[64] = {0};
// Careful about endian issues.
sp_svg_write_color( c, sizeof(c),
0xff // can't have transparency in the color itself
//0x0ff & (data->data[3] >> 8),
));
bool updatePerformed = false;
// piggie-backed palette entry info
for ( int i = 0; i < dataVals[6]; i++ ) {
}
// Now hook in a magic tag of some sort.
str = 0;
false );
item->updateRepr();
updatePerformed = true;
}
}
if ( !updatePerformed ) {
}
item->updateRepr();
_("Drop color"));
if ( srgbProf ) {
}
}
}
}
break;
#endif // ENABLE_MAGIC_COLORS
case APP_X_COLOR:
{
int destX = 0;
int destY = 0;
// Careful about endian issues.
0xff // can't have transparency in the color itself
//0x0ff & (data->data[3] >> 8),
));
bool consumed = false;
if (consumed) {
}
}
//if (!consumed && tools_active(desktop, TOOLS_TEXT)) {
// consumed = sp_text_context_drop_color(c, button_doc);
// if (consumed) {
// sp_document_done( doc , SP_VERB_NONE, _("Drop color on gradient stop"));
// }
//}
if (fillnotstroke &&
boost::optional<Path::cut_position> position = get_nearest_position_on_Path(livarot_path, button_doc);
if (position) {
double stroke_tolerance =
desktop->current_zoom() *
: 0.0)
fillnotstroke = false;
}
}
delete livarot_path;
}
item->updateRepr();
_("Drop color"));
}
}
}
break;
case APP_OSWB_COLOR:
{
bool worked = false;
if ( worked ) {
colorspec = "none";
} else {
SPGradient* matches = 0;
break;
}
}
}
if (matches) {
colorspec = "url(#";
colorspec += ")";
} else {
}
}
}
}
if ( worked ) {
int destX = 0;
int destY = 0;
bool consumed = false;
if (consumed) {
}
}
if (fillnotstroke &&
boost::optional<Path::cut_position> position = get_nearest_position_on_Path(livarot_path, button_doc);
if (position) {
double stroke_tolerance =
desktop->current_zoom() *
: 0.0)
fillnotstroke = false;
}
}
delete livarot_path;
}
item->updateRepr();
_("Drop color"));
}
}
}
break;
case SVG_DATA:
case SVG_XML_DATA: {
sp_ui_error_dialog(_("Could not parse SVG data"));
return;
}
}
// Add it to the current layer
// Greg's edits to add intelligent positioning of svg drops
// move to mouse pointer
{
if (sel_bbox) {
sp_selection_move_relative(selection, m, false);
}
}
_("Drop SVG"));
break;
}
case URI_LIST: {
break;
}
case PNG_DATA:
case JPEG_DATA:
case IMAGE_DATA: {
++i;
}
_("Drop bitmap image"));
break;
}
}
}
#include "gradient-context.h"
GdkDragContext */*drag_context*/,
GtkSelectionData */*data*/,
guint /*info*/,
guint /*event_time*/,
gpointer /*user_data*/)
{
// SPDocument *doc = SP_ACTIVE_DOCUMENT;
// SPDesktop *desktop = SP_ACTIVE_DESKTOP;
// g_message("drag-n-drop motion (%4d, %4d) at %d", x, y, event_time);
}
GdkDragContext */*drag_context*/,
guint /*event_time*/,
gpointer /*user_data*/ )
{
// g_message("drag-n-drop leave at %d", event_time);
}
static void
{
if (!list)
return;
}
static void
{
if (filename) {
sp_ui_import_one_file((char const *)filename);
}
}
static void
sp_ui_import_one_file(char const *filename)
{
if (!doc) return;
// Pass off to common implementation
// TODO might need to get the proper type of Inkscape::Extension::Extension
}
void
{
}
bool
{
bool return_value = FALSE;
_( "<span weight=\"bold\" size=\"larger\">A file named \"%s\" already exists. Do you want to replace it?</span>\n\n"
"The file already exists in \"%s\". Replacing it will overwrite its contents." ),
);
_("Replace"), GTK_RESPONSE_YES,
NULL );
return_value = TRUE;
} else {
}
} else {
return_value = TRUE;
}
return return_value;
}
static void
{
}
static void
{
//child is either
//- a GtkHBox, whose first child is a label displaying name if the menu
//item has an accel key
//- a GtkLabel if the menu has no accel key
if (GTK_IS_LABEL(child)) {
} else if (GTK_IS_HBOX(child)) {
}//else sp_ui_menu_append_item_from_verb has been modified and can set
//a menu item in yet another way...
}
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :