1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /** @file
3  * Entry widget for typing color value in css form
4  *//*
5  * Authors:
6  *   Tomasz Boczkowski <penginsbacon@gmail.com>
7  *
8  * Copyright (C) 2014 Authors
9  * Released under GNU GPL v2+, read the file 'COPYING' for more information.
10  */
11 #include <glibmm.h>
12 #include <glibmm/i18n.h>
13 #include <iomanip>
14 
15 #include "color-entry.h"
16 
17 namespace Inkscape {
18 namespace UI {
19 namespace Widget {
20 
ColorEntry(SelectedColor & color)21 ColorEntry::ColorEntry(SelectedColor &color)
22     : _color(color)
23     , _updating(false)
24     , _updatingrgba(false)
25     , _prevpos(0)
26     , _lastcolor(0)
27 {
28     _color_changed_connection = color.signal_changed.connect(sigc::mem_fun(this, &ColorEntry::_onColorChanged));
29     _color_dragged_connection = color.signal_dragged.connect(sigc::mem_fun(this, &ColorEntry::_onColorChanged));
30     signal_activate().connect(sigc::mem_fun(this, &ColorEntry::_onColorChanged));
31     get_buffer()->signal_inserted_text().connect(sigc::mem_fun(this, &ColorEntry::_inputCheck));
32     _onColorChanged();
33 
34     // add extra character for pasting a hash, '#11223344'
35     set_max_length(9);
36     set_width_chars(8);
37     set_tooltip_text(_("Hexadecimal RGBA value of the color"));
38 }
39 
~ColorEntry()40 ColorEntry::~ColorEntry()
41 {
42     _color_changed_connection.disconnect();
43     _color_dragged_connection.disconnect();
44 }
45 
_inputCheck(guint pos,const gchar *,guint n_chars)46 void ColorEntry::_inputCheck(guint pos, const gchar * /*chars*/, guint n_chars)
47 {
48     // remember position of last character, so we can remove it.
49     // we only overflow by 1 character at most.
50     _prevpos = pos + n_chars - 1;
51 }
52 
on_changed()53 void ColorEntry::on_changed()
54 {
55     if (_updating) {
56         return;
57     }
58     if (_updatingrgba) {
59         return;  // Typing text into entry box
60     }
61 
62     Glib::ustring text = get_text();
63     bool changed = false;
64 
65     // Coerce the value format to hexadecimal
66     for (auto it = text.begin(); it != text.end(); /*++it*/) {
67         if (!g_ascii_isxdigit(*it)) {
68             text.erase(it);
69             changed = true;
70         } else {
71             ++it;
72         }
73     }
74 
75     if (text.size() > 8) {
76         text.erase(_prevpos, 1);
77         changed = true;
78     }
79 
80     // autofill rules
81     gchar *str = g_strdup(text.c_str());
82     gchar *end = nullptr;
83     guint64 rgba = g_ascii_strtoull(str, &end, 16);
84     ptrdiff_t len = end - str;
85     if (len < 8) {
86         if (len == 0) {
87             rgba = _lastcolor;
88         } else if (len <= 2) {
89             if (len == 1) {
90                 rgba *= 17;
91             }
92             rgba = (rgba << 24) + (rgba << 16) + (rgba << 8);
93         } else if (len <= 4) {
94             // display as rrggbbaa
95             rgba = rgba << (4 * (4 - len));
96             guint64 r = rgba & 0xf000;
97             guint64 g = rgba & 0x0f00;
98             guint64 b = rgba & 0x00f0;
99             guint64 a = rgba & 0x000f;
100             rgba = 17 * ((r << 12) + (g << 8) + (b << 4) + a);
101         } else {
102             rgba = rgba << (4 * (8 - len));
103         }
104 
105         if (len == 7) {
106             rgba = (rgba & 0xfffffff0) + (_lastcolor & 0x00f);
107         } else if (len == 5) {
108             rgba = (rgba & 0xfffff000) + (_lastcolor & 0xfff);
109         } else if (len != 4 && len != 8) {
110             rgba = (rgba & 0xffffff00) + (_lastcolor & 0x0ff);
111         }
112     }
113 
114     _updatingrgba = true;
115     if (changed) {
116         set_text(str);
117     }
118     SPColor color(rgba);
119     _color.setColorAlpha(color, SP_RGBA32_A_F(rgba));
120     _updatingrgba = false;
121 
122     g_free(str);
123 }
124 
125 
_onColorChanged()126 void ColorEntry::_onColorChanged()
127 {
128     if (_updatingrgba) {
129         return;
130     }
131 
132     SPColor color = _color.color();
133     gdouble alpha = _color.alpha();
134 
135     _lastcolor = color.toRGBA32(alpha);
136     Glib::ustring text = Glib::ustring::format(std::hex, std::setw(8), std::setfill(L'0'), _lastcolor);
137 
138     Glib::ustring old_text = get_text();
139     if (old_text != text) {
140         _updating = true;
141         set_text(text);
142         _updating = false;
143     }
144 }
145 }
146 }
147 }
148 /*
149   Local Variables:
150   mode:c++
151   c-file-style:"stroustrup"
152   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
153   indent-tabs-mode:nil
154   fill-column:99
155   End:
156 */
157 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
158