selected-style.cpp revision 0bc4bf328ef4f9e6405a72e46ac36d9548f13eb4
/*
* Author:
* buliabyak@gmail.com
* Abhishek Sharma
* Jon A. Cruz <jon@joncruz.org>
*
* Copyright (C) 2005 author
*
* Released under GNU GPL. Read the file 'COPYING' for more information.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "selected-style.h"
#include <gtkmm/separatormenuitem.h>
#include "widgets/spw-utilities.h"
#include "ui/widget/color-preview.h"
#include "selection.h"
#include "desktop-handles.h"
#include "style.h"
#include "desktop-style.h"
#include "sp-namedview.h"
#include "sp-linear-gradient.h"
#include "sp-radial-gradient.h"
#include "sp-pattern.h"
#include "ui/dialog/dialog-manager.h"
#include "ui/dialog/fill-and-stroke.h"
#include "ui/dialog/panel-dialog.h"
#include "document.h"
#include "document-undo.h"
#include "widgets/widget-sizes.h"
#include "widgets/spinbutton-events.h"
#include "widgets/gradient-image.h"
#include "sp-gradient.h"
#include "svg/svg-color.h"
#include "svg/css-ostringstream.h"
#include "ui/tools/tool-base.h"
#include "message-context.h"
#include "verbs.h"
#include "color.h"
#include <display/sp-canvas.h>
#include "pixmaps/cursor-adj-h.xpm"
#include "pixmaps/cursor-adj-s.xpm"
#include "pixmaps/cursor-adj-l.xpm"
#include "pixmaps/cursor-adj-a.xpm"
#include "sp-cursor.h"
#include "gradient-chemistry.h"
static gdouble const _sw_presets[] = { 32 , 16 , 10 , 8 , 6 , 4 , 3 , 2 , 1.5 , 1 , 0.75 , 0.5 , 0.25 , 0.1 };
static gchar const *const _sw_presets_str[] = {"32", "16", "10", "8", "6", "4", "3", "2", "1.5", "1", "0.75", "0.5", "0.25", "0.1"};
static void
{
}
static void
{
}
static void
{
}
namespace {
{
widget.set_has_tooltip(false);
}
} // namespace
namespace Inkscape {
namespace UI {
namespace Widget {
typedef struct {
int item;
} DropTracker;
/* Drag and Drop */
typedef enum {
//TODO: warning: deprecated conversion from string constant to ‘gchar*’
//
//Turn out to be warnings that we should probably leave in place. The
// code, those warnings are actually desired. They say "Hey! Fix this". We
static const GtkTargetEntry ui_drop_target_entries [] = {
{"application/x-color", 0, APP_X_COLOR}
};
#define ENTRIES_SIZE(n) sizeof(n)/sizeof(n[0])
/* convenience function */
:
#if WITH_GTKMM_3_0
_table(),
#else
#endif
_fill_label (_("Fill:")),
_stroke_label (_("Stroke:")),
_opacity_label (_("O:")),
_fill_place(this, SS_FILL),
_stroke_place(this, SS_STROKE),
_fill_flag_place (),
_opacity_place (),
#if WITH_GTKMM_3_0
#else
#endif
_opacity_sb (0.02, 0),
_stroke (),
_stroke_width_place(this),
_stroke_width (""),
_opacity_blocked (false),
{
_fill_label.set_padding(0, 0);
_stroke_label.set_padding(0, 0);
_opacity_label.set_padding(0, 0);
#if WITH_GTKMM_3_0
#else
_table.set_row_spacings (0);
#endif
__na[i] = (_("Nothing selected"));
__none[i] = (i == SS_FILL)? (C_("Fill and stroke", "No fill")) : (C_("Fill and stroke", "No stroke"));
_lgradient[i].show_all();
_gradient_box_l[i].show_all();
_rgradient[i].show_all();
_gradient_box_r[i].show_all();
// TRANSLATOR COMMENT: A means "Averaged"
__averaged[i] = (i == SS_FILL)? (_("Fill is averaged over selected objects")) : (_("Stroke is averaged over selected objects"));
// TRANSLATOR COMMENT: M means "Multiple"
__multiple[i] = (i == SS_FILL)? (_("Multiple selected objects have the same fill")) : (_("Multiple selected objects have the same stroke"));
_popup_edit[i].add(*(new Gtk::Label((i == SS_FILL)? _("Edit fill...") : _("Edit stroke..."), 0.0, 0.5)));
_popup_opaque[i].add(*(new Gtk::Label((i == SS_FILL)? _("Make fill opaque") : _("Make stroke opaque"), 0.0, 0.5)));
//TRANSLATORS COMMENT: unset is a verb here
_popup_unset[i].add(*(new Gtk::Label((i == SS_FILL)? _("Unset fill") : _("Unset stroke"), 0.0, 0.5)));
_popup_remove[i].add(*(new Gtk::Label((i == SS_FILL)? _("Remove fill") : _("Remove stroke"), 0.0, 0.5)));
_popup_copy[i].set_sensitive(false);
}
{
int row = 0;
mi->signal_activate().connect(sigc::bind<Inkscape::Util::Unit const *>(sigc::mem_fun(*this, &SelectedStyle::on_popup_units), u));
row++;
++iter;
}
row++;
mi->signal_activate().connect(sigc::bind<int>(sigc::mem_fun(*this, &SelectedStyle::on_popup_preset), i));
row++;
}
row++;
row++;
}
_fill_place.signal_button_release_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_fill_click));
_stroke_place.signal_button_release_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_stroke_click));
_opacity_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_opacity_click));
_stroke_width_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_sw_click));
_stroke_width_place.signal_button_release_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_sw_click));
_opacity_sb.signal_value_changed().connect(sigc::mem_fun(*this, &SelectedStyle::on_opacity_changed));
// Connect to key-press to ensure focus is consistent with other spin buttons when using the keys vs mouse-click
g_signal_connect (G_OBJECT (_opacity_sb.gobj()), "key-press-event", G_CALLBACK (spinbutton_keypress), _opacity_sb.gobj());
g_signal_connect (G_OBJECT (_opacity_sb.gobj()), "focus-in-event", G_CALLBACK (spinbutton_focus_in), _opacity_sb.gobj());
_opacity_sb.set_sensitive (false);
#if WITH_GTKMM_3_0
#else
#endif
#if WITH_GTKMM_3_0
#else
#endif
"drag_data_received",
"drag_data_received",
}
{
delete selection_changed_connection;
delete selection_modified_connection;
delete subselection_changed_connection;
delete _color_preview[i];
// FIXME: do we need this? the destroy methods are not exported
//sp_gradient_image_destroy(GTK_OBJECT(_gradient_preview_l[i]));
//sp_gradient_image_destroy(GTK_OBJECT(_gradient_preview_r[i]));
}
}
void
{
this )
));
this )
));
this )
));
// Set the doc default unit active in the units list
for (int i = 0; i < length; i++) {
mi->set_active();
break;
}
}
}
GdkDragContext */*drag_context*/,
guint /*info*/,
guint /*event_time*/,
{
case SS_FILL:
case SS_STROKE:
{
gchar c[64];
// 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),
));
_("Drop color"));
}
}
break;
}
}
void SelectedStyle::on_fill_remove() {
_("Remove fill"));
}
void SelectedStyle::on_stroke_remove() {
_("Remove stroke"));
}
void SelectedStyle::on_fill_unset() {
_("Unset fill"));
}
void SelectedStyle::on_stroke_unset() {
_("Unset stroke"));
}
void SelectedStyle::on_fill_opaque() {
_("Make fill opaque"));
}
void SelectedStyle::on_stroke_opaque() {
_("Make fill opaque"));
}
void SelectedStyle::on_fill_lastused() {
gchar c[64];
sp_svg_write_color (c, sizeof(c), color);
_("Apply last set color to fill"));
}
void SelectedStyle::on_stroke_lastused() {
gchar c[64];
sp_svg_write_color (c, sizeof(c), color);
_("Apply last set color to stroke"));
}
void SelectedStyle::on_fill_lastselected() {
gchar c[64];
_("Apply last selected color to fill"));
}
void SelectedStyle::on_stroke_lastselected() {
gchar c[64];
_("Apply last selected color to stroke"));
}
void SelectedStyle::on_fill_invert() {
gchar c[64];
return;
}
sp_svg_write_color (c, sizeof(c),
)
);
_("Invert fill"));
}
void SelectedStyle::on_stroke_invert() {
gchar c[64];
return;
}
sp_svg_write_color (c, sizeof(c),
)
);
_("Invert stroke"));
}
void SelectedStyle::on_fill_white() {
gchar c[64];
sp_svg_write_color (c, sizeof(c), 0xffffffff);
_("White fill"));
}
void SelectedStyle::on_stroke_white() {
gchar c[64];
sp_svg_write_color (c, sizeof(c), 0xffffffff);
_("White stroke"));
}
void SelectedStyle::on_fill_black() {
gchar c[64];
sp_svg_write_color (c, sizeof(c), 0x000000ff);
_("Black fill"));
}
void SelectedStyle::on_stroke_black() {
gchar c[64];
sp_svg_write_color (c, sizeof(c), 0x000000ff);
_("Black stroke"));
}
void SelectedStyle::on_fill_copy() {
gchar c[64];
text += c;
}
}
}
void SelectedStyle::on_stroke_copy() {
gchar c[64];
text += c;
}
}
}
void SelectedStyle::on_fill_paste() {
guint32 color = sp_svg_read_color(text.c_str(), 0x000000ff); // impossible value, as SVG color cannot have opacity
return;
_("Paste fill"));
}
}
void SelectedStyle::on_stroke_paste() {
guint32 color = sp_svg_read_color(text.c_str(), 0x000000ff); // impossible value, as SVG color cannot have opacity
return;
_("Paste stroke"));
}
}
void SelectedStyle::on_fillstroke_swap() {
case SS_NA:
case SS_MANY:
break;
case SS_NONE:
break;
case SS_UNSET:
break;
case SS_COLOR:
gchar c[64];
break;
case SS_LGRADIENT:
case SS_RGRADIENT:
case SS_PATTERN:
break;
}
case SS_NA:
case SS_MANY:
break;
case SS_NONE:
break;
case SS_UNSET:
break;
case SS_COLOR:
gchar c[64];
break;
case SS_LGRADIENT:
case SS_RGRADIENT:
case SS_PATTERN:
break;
}
_("Swap fill and stroke"));
}
void SelectedStyle::on_fill_edit() {
fs->showPageFill();
}
void SelectedStyle::on_stroke_edit() {
}
bool
{
fs->showPageFill();
} else {
}
}
return true;
}
bool
{
} else {
}
}
return true;
}
bool
{
//
}
return true;
}
bool
{
const char* opacity = _opacity_sb.get_value() < 50? "0.5" : (_opacity_sb.get_value() == 100? "0" : "1");
_("Change opacity"));
return true;
}
return false;
}
update();
}
void SelectedStyle::on_popup_preset(int i) {
gdouble w;
if (_sw_unit) {
} else {
w = _sw_presets[i];
}
os << w;
// FIXME: update dash patterns!
_("Change stroke width"));
}
void
{
return;
// create temporary style
flag_place->remove();
_paintserver_id[i].clear();
_popup_copy[i].set_sensitive(false);
// query style from desktop. This returns a result flag and fills query with the style of subselection, if any, or selection
switch (result) {
case QUERY_STYLE_NOTHING:
if ( _dropEnabled[i] ) {
_dropEnabled[i] = false;
}
break;
case QUERY_STYLE_SINGLE:
if ( !_dropEnabled[i] ) {
_dropEnabled[i] = true;
}
if (i == SS_FILL) {
} else {
}
SPPaintServer *server = (i == SS_FILL)? SP_STYLE_FILL_SERVER (query) : SP_STYLE_STROKE_SERVER (query);
if ( server ) {
_paintserver_id[i] += "url(#";
_paintserver_id[i] += ")";
if (SP_IS_LINEARGRADIENT (server)) {
_mode[i] = SS_LGRADIENT;
} else if (SP_IS_RADIALGRADIENT (server)) {
_mode[i] = SS_RGRADIENT;
} else if (SP_IS_PATTERN (server)) {
_mode[i] = SS_PATTERN;
}
} else {
}
_lastselected[i] = _thisselected[i];
_color_preview[i]->show_all();
_popup_copy[i].set_sensitive(true);
}
if (result == QUERY_STYLE_MULTIPLE_AVERAGED) {
} else if (result == QUERY_STYLE_MULTIPLE_SAME) {
}
break;
break;
default:
break;
}
}
// Now query opacity
switch (result) {
case QUERY_STYLE_NOTHING:
_opacity_sb.set_sensitive(false);
break;
case QUERY_STYLE_SINGLE:
if (_opacity_blocked) break;
_opacity_blocked = true;
_opacity_sb.set_sensitive(true);
#if WITH_GTKMM_3_0
#else
#endif
_opacity_blocked = false;
break;
}
// Now query stroke_width
switch (result_sw) {
case QUERY_STYLE_NOTHING:
current_stroke_width = 0;
break;
case QUERY_STYLE_SINGLE:
{
double w;
if (_sw_unit) {
} else {
}
current_stroke_width = w;
{
}
{
w,
_(" (averaged)") : "");
}
break;
}
default:
break;
}
}
for (Glib::ListHandle<Gtk::Widget *>::iterator iter = children.begin(); iter != children.end(); ++iter) {
}
{
}
{
}
{
}
{
}
{
}
}
void SelectedStyle::on_opacity_changed () {
if (_opacity_blocked)
return;
_opacity_blocked = true;
#if WITH_GTKMM_3_0
#else
#endif
// FIXME: workaround for GTK breakage: display interruptibility sometimes results in GTK
// sending multiple value-changed events. As if when Inkscape interrupts redraw for main loop
// iterations, GTK discovers that this callback hasn't finished yet, and for some weird reason
// decides to add yet another value-changed event to the queue. Totally braindead if you ask
// me. As a result, scrolling the spinbutton once results in runaway change until it hits 1.0
// or 0.0. (And no, this is not a race with ::update, I checked that.)
// Sigh. So we disable interruptibility while we're setting the new value.
DocumentUndo::maybeDone(sp_desktop_document(_desktop), "fillstroke:opacity", SP_VERB_DIALOG_FILL_STROKE,
_("Change opacity"));
// resume interruptibility
_opacity_blocked = false;
}
/* ============================================= RotateableSwatch */
startcolor(0),
startcolor_set(false),
undokey("ssrot1"),
cr(0),
cr_set(false)
{
}
}
double
{
double diff = 0;
if (by > 0) {
} else {
}
if (by > 0) {
} else {
}
if (hsla[3] < 0) {
hsla[3] = 0;
}
} else { // hue
while (hsla[0] < 0)
hsla[0] += 1;
while (hsla[0] > 1)
hsla[0] -= 1;
}
float rgb[3];
gchar c[64];
sp_svg_write_color (c, sizeof(c),
(SP_COLOR_F_TO_U(rgb[0])),
0xff
)
);
sp_repr_css_set_property(css, (fillstroke == SS_FILL) ? "fill-opacity" : "stroke-opacity", osalpha.str().c_str());
} else {
}
return diff;
}
void
return;
} else { // hue
}
#if GTK_CHECK_VERSION(3,0,0)
#else
#endif
cr_set = true;
}
}
if (!startcolor_set) {
startcolor_set = true;
} else {
cc = startcolor;
}
float hsla[4];
double diff = 0;
SP_VERB_DIALOG_FILL_STROKE, (_("Adjust alpha")));
parent->getDesktop()->event_context->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adjusting <b>alpha</b>: was %.3g, now <b>%.3g</b> (diff %.3g); with <b>Ctrl</b> to adjust lightness, with <b>Shift</b> to adjust saturation, without modifiers to adjust hue"), ch - diff, ch, diff);
SP_VERB_DIALOG_FILL_STROKE, (_("Adjust saturation")));
parent->getDesktop()->event_context->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adjusting <b>saturation</b>: was %.3g, now <b>%.3g</b> (diff %.3g); with <b>Ctrl</b> to adjust lightness, with <b>Alt</b> to adjust alpha, without modifiers to adjust hue"), ch - diff, ch, diff);
SP_VERB_DIALOG_FILL_STROKE, (_("Adjust lightness")));
parent->getDesktop()->event_context->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adjusting <b>lightness</b>: was %.3g, now <b>%.3g</b> (diff %.3g); with <b>Shift</b> to adjust saturation, with <b>Alt</b> to adjust alpha, without modifiers to adjust hue"), ch - diff, ch, diff);
} else { // hue
SP_VERB_DIALOG_FILL_STROKE, (_("Adjust hue")));
parent->getDesktop()->event_context->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adjusting <b>hue</b>: was %.3g, now <b>%.3g</b> (diff %.3g); with <b>Shift</b> to adjust saturation, with <b>Alt</b> to adjust alpha, with <b>Ctrl</b> to adjust lightness"), ch - diff, ch, diff);
}
}
void
}
void
return;
float hsla[4];
if (cr_set) {
if (cr) {
#if GTK_CHECK_VERSION(3,0,0)
#else
#endif
}
cr_set = false;
}
SP_VERB_DIALOG_FILL_STROKE, ("Adjust alpha"));
SP_VERB_DIALOG_FILL_STROKE, ("Adjust saturation"));
SP_VERB_DIALOG_FILL_STROKE, ("Adjust lightness"));
} else { // hue
SP_VERB_DIALOG_FILL_STROKE, ("Adjust hue"));
}
undokey = "ssrot2";
} else {
undokey = "ssrot1";
}
startcolor_set = false;
}
/* ============================================= RotateableStrokeWidth */
startvalue(0),
startvalue_set(false),
undokey("swrot1")
{
}
}
double
{
double newval;
// by is -1..1
if (by < 0) {
// map negative 0..-1 to current..0
} else {
// map positive 0..1 to current..4*current
}
// if dragged into zero and this is the final adjust on mouse release, delete stroke;
// if it's not final, leave it a chance to increase again (which is not possible with "none")
} else {
}
}
void
// if this is the first motion after a mouse grab, remember the current width
if (!startvalue_set) {
// if it's 0, adjusting (which uses multiplication) will not be able to change it, so we
// cheat and provide a non-zero value
if (startvalue == 0)
startvalue = 1;
startvalue_set = true;
}
} else {
SP_VERB_DIALOG_FILL_STROKE, (_("Adjust stroke width")));
parent->getDesktop()->event_context->message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adjusting <b>stroke width</b>: was %.3g, now <b>%.3g</b> (diff %.3g)"), startvalue, startvalue + diff, diff);
}
}
void
} else {
startvalue_set = false;
SP_VERB_DIALOG_FILL_STROKE, (_("Adjust stroke width")));
}
undokey = "swrot2";
} else {
undokey = "swrot1";
}
}
void
startvalue_set = false;
}
{
try {
return &fill_and_stroke;
}
return 0;
}
} // namespace Widget
} // namespace UI
} // namespace Inkscape
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :