17
17
* Authored by: Manuel de la Pena <manuel.delapena@canonical.com>
20
21
#include "TextInput.h"
21
#include "unity-shared/IconTexture.h"
22
#include "unity-shared/DashStyle.h"
23
#include "unity-shared/RawPixel.h"
24
#include "unity-shared/PreviewStyle.h"
25
#include "unity-shared/TextureCache.h"
24
#include <glib/gi18n-lib.h>
26
#include <Nux/LayeredLayout.h>
27
#include <Nux/HLayout.h>
28
#include <Nux/VLayout.h>
29
#include <NuxCore/Logger.h>
31
#include "CairoTexture.h"
32
#include "StaticCairoText.h"
33
#include "IconTexture.h"
34
#include "IMTextEntry.h"
35
#include "DashStyle.h"
36
#include "PreviewStyle.h"
38
#include "TextureCache.h"
39
#include "UnitySettings.h"
32
const float kExpandDefaultIconOpacity = 1.0f;
34
const int SPACE_BETWEEN_ENTRY_AND_HIGHLIGHT = 10;
35
const int LEFT_INTERNAL_PADDING = 6;
36
const int TEXT_INPUT_RIGHT_BORDER = 10;
38
const int HIGHLIGHT_HEIGHT = 24;
46
const int BORDER_RADIUS = 5;
47
const int TOOLTIP_WAIT = 500;
48
const RawPixel SPACE_BETWEEN_ENTRY_AND_HIGHLIGHT = 10_em;
49
const RawPixel LEFT_INTERNAL_PADDING = 6_em;
50
const RawPixel TEXT_INPUT_RIGHT_BORDER = 10_em;
51
const RawPixel HINT_PADDING = 3_em;
40
53
const RawPixel TOOLTIP_Y_OFFSET = 3_em;
41
54
const RawPixel TOOLTIP_OFFSET = 10_em;
47
60
const int HINT_LABEL_FONT_SIZE = 11;
49
62
const std::string PANGO_ENTRY_DEFAULT_FONT_FAMILY = "Ubuntu";
50
const int PANGO_ENTRY_FONT_SIZE = 14;
63
const RawPixel PANGO_ENTRY_FONT_SIZE = 14_em;
54
65
nux::logging::Logger logger("unity.textinput");
56
NUX_IMPLEMENT_OBJECT_TYPE(TextInput);
58
nux::AbstractPaintLayer* CreateWarningLayer(nux::BaseTexture* texture)
67
std::shared_ptr<nux::AbstractPaintLayer> CreateWarningLayer(nux::BaseTexture* texture)
60
69
// Create the texture layer
61
70
nux::TexCoordXForm texxform;
71
80
rop.SrcBlend = GL_ONE;
72
81
rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA;
74
return (new nux::TextureLayer(texture->GetDeviceTexture(),
83
return std::make_shared<nux::TextureLayer>(texture->GetDeviceTexture(), texxform, nux::color::White, true, rop);
87
NUX_IMPLEMENT_OBJECT_TYPE(TextInput);
81
89
TextInput::TextInput(NUX_FILE_LINE_DECL)
82
90
: View(NUX_FILE_LINE_PARAM)
85
93
, hint_font_size(HINT_LABEL_FONT_SIZE)
86
94
, show_activator(false)
87
95
, show_caps_lock(false)
88
97
, bg_layer_(new nux::ColorLayer(nux::Color(0xff595853), true))
89
98
, caps_lock_on(false)
91
100
, last_height_(-1)
92
, mouse_over_warning_icon_(false)
94
102
layout_ = new nux::HLayout(NUX_TRACKER_LOCATION);
95
layout_->SetLeftAndRightPadding(LEFT_INTERNAL_PADDING, TEXT_INPUT_RIGHT_BORDER);
96
layout_->SetSpaceBetweenChildren(SPACE_BETWEEN_ENTRY_AND_HIGHLIGHT);
103
layout_->SetLeftAndRightPadding(LEFT_INTERNAL_PADDING.CP(scale), TEXT_INPUT_RIGHT_BORDER.CP(scale));
104
layout_->SetSpaceBetweenChildren(SPACE_BETWEEN_ENTRY_AND_HIGHLIGHT.CP(scale));
97
105
SetLayout(layout_);
99
nux::HLayout* hint_layout = new nux::HLayout(NUX_TRACKER_LOCATION);
100
hint_layout->SetLeftAndRightPadding(3, 3);
107
hint_layout_ = new nux::HLayout(NUX_TRACKER_LOCATION);
108
hint_layout_->SetLeftAndRightPadding(HINT_PADDING.CP(scale), HINT_PADDING.CP(scale));
102
110
hint_ = new StaticCairoText("");
103
111
hint_->SetTextColor(nux::Color(1.0f, 1.0f, 1.0f, 0.5f));
104
hint_layout->AddView(hint_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL);
112
hint_->SetScale(scale);
113
hint_layout_->AddView(hint_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL);
105
114
hint_font_name.changed.connect(sigc::hide(sigc::mem_fun(this, &TextInput::UpdateHintFont)));
106
115
hint_font_size.changed.connect(sigc::hide(sigc::mem_fun(this, &TextInput::UpdateHintFont)));
107
116
UpdateHintFont();
109
118
pango_entry_ = new IMTextEntry();
110
119
pango_entry_->SetFontFamily(PANGO_ENTRY_DEFAULT_FONT_FAMILY.c_str());
111
pango_entry_->SetFontSize(PANGO_ENTRY_FONT_SIZE);
112
120
pango_entry_->cursor_moved.connect([this](int i) { QueueDraw(); });
113
121
pango_entry_->mouse_down.connect(sigc::mem_fun(this, &TextInput::OnMouseButtonDown));
114
122
pango_entry_->end_key_focus.connect(sigc::mem_fun(this, &TextInput::OnEndKeyFocus));
119
127
layered_layout_ = new nux::LayeredLayout();
120
layered_layout_->AddLayer(hint_layout);
128
layered_layout_->AddLayer(hint_layout_);
121
129
layered_layout_->AddLayer(pango_entry_);
122
130
layered_layout_->SetPaintAll(true);
123
131
layered_layout_->SetActiveLayerN(1);
124
132
layout_->AddView(layered_layout_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FIX);
126
136
// Caps lock warning
127
warning_ = new IconTexture(LoadWarningIcon(DEFAULT_ICON_SIZE));
137
warning_ = new IconTexture(LoadWarningIcon(DEFAULT_ICON_SIZE.CP(scale)));
128
138
warning_->SetVisible(caps_lock_on());
129
139
layout_->AddView(warning_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL);
130
140
caps_lock_on.changed.connect([this] (bool on) {
139
show_caps_lock.changed.connect([this] (bool changed) {
140
if (!warning_tooltip_.IsValid())
141
LoadWarningTooltip();
149
show_caps_lock.changed.connect(sigc::hide(sigc::mem_fun(this, &TextInput::CheckIfCapsLockOn)));
150
scale.changed.connect(sigc::mem_fun(this, &TextInput::UpdateScale));
151
Settings::Instance().font_scaling.changed.connect(sigc::hide(sigc::mem_fun(this, &TextInput::UpdateSize)));
147
activator_ = new IconTexture(LoadActivatorIcon(DEFAULT_ICON_SIZE));
154
activator_ = new IconTexture(LoadActivatorIcon(DEFAULT_ICON_SIZE.CP(scale)));
148
155
activator_->SetVisible(show_activator());
149
156
layout_->AddView(activator_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL);
160
167
spinner_ = new SearchBarSpinner();
161
168
spinner_->SetVisible(false);
162
spinner_->SetMinMaxSize(22, 22);
169
spinner_->scale = scale();
163
170
layout_->AddView(spinner_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL);
165
sig_manager_.Add<void, GtkSettings*, GParamSpec*>(gtk_settings_get_default(),
166
"notify::gtk-font-name", sigc::mem_fun(this, &TextInput::OnFontChanged));
167
OnFontChanged(gtk_settings_get_default());
172
sig_manager_.Add<void, GtkSettings*>(gtk_settings_get_default(), "notify::gtk-font-name", sigc::hide(sigc::mem_fun(this, &TextInput::OnFontChanged)));
175
sig_manager_.Add<void, GdkKeymap*>(gdk_keymap_get_default(), "state-changed", [this](GdkKeymap*) {
169
179
sig_manager_.Add<void, GdkKeymap*>(gdk_keymap_get_default(), "state-changed", [this](GdkKeymap*) {
170
180
CheckIfCapsLockOn();
177
187
input_hint.changed.connect([this](std::string const& s) { OnInputHintChanged(); });
179
189
warning_->mouse_enter.connect([this] (int x, int y, int button, int key_flags) {
180
mouse_over_warning_icon_ = true;
190
tooltip_timeout_.reset(new glib::Timeout(TOOLTIP_WAIT, [this] {
191
tooltip_timeout_.reset();
184
197
warning_->mouse_leave.connect([this] (int x, int y, int button, int key_flags) {
185
mouse_over_warning_icon_ = false;
198
tooltip_timeout_ ? tooltip_timeout_.reset() : QueueDraw();
202
void TextInput::UpdateSize()
204
pango_entry_->SetFontSize(PANGO_ENTRY_FONT_SIZE.CP(scale * Settings::Instance().font_scaling()));
205
int entry_min = pango_entry_->GetMinimumHeight();
206
pango_entry_->SetMaximumHeight(entry_min);
207
layered_layout_->SetMinimumHeight(entry_min);
208
layered_layout_->SetMaximumHeight(entry_min);
211
void TextInput::UpdateScale(double scale)
213
layout_->SetLeftAndRightPadding(LEFT_INTERNAL_PADDING.CP(scale), TEXT_INPUT_RIGHT_BORDER.CP(scale));
214
layout_->SetSpaceBetweenChildren(SPACE_BETWEEN_ENTRY_AND_HIGHLIGHT.CP(scale));
218
hint_layout_->SetLeftAndRightPadding(HINT_PADDING.CP(scale), HINT_PADDING.CP(scale));
219
hint_->SetScale(scale);
220
hint_->SetMaximumHeight(pango_entry_->GetMinimumHeight());
222
spinner_->scale = scale;
223
activator_->SetTexture(LoadActivatorIcon(DEFAULT_ICON_SIZE.CP(scale)));
224
warning_->SetTexture(LoadWarningIcon(DEFAULT_ICON_SIZE.CP(scale)));
225
warning_tooltip_.Release();
190
231
void TextInput::CheckIfCapsLockOn()
192
233
GdkKeymap* keymap = gdk_keymap_get_default();
196
237
void TextInput::SetSpinnerVisible(bool visible)
198
239
spinner_->SetVisible(visible);
201
activator_->SetVisible(false);
203
activator_->SetVisible(show_activator());
240
activator_->SetVisible(!visible && show_activator());
206
243
void TextInput::SetSpinnerState(SpinnerState spinner_state)
268
305
std::shared_ptr<PangoFontDescription> desc(pango_font_description_from_string(font_name), pango_font_description_free);
269
306
pango_context_set_font_description(context, desc.get());
270
307
pango_context_set_language(context, gtk_get_default_language());
308
pango_cairo_context_set_resolution(context, 96.0 * Settings::Instance().font_scaling());
272
310
pango_layout_set_height(layout, -1); //avoid wrap lines
273
311
pango_layout_set_text(layout, _("Caps lock is on"), -1);
277
315
extents.width += TOOLTIP_OFFSET;
278
316
extents.height += TOOLTIP_OFFSET;
280
nux::CairoGraphics cg(CAIRO_FORMAT_ARGB32, extents.width, extents.height);
318
nux::CairoGraphics cg(CAIRO_FORMAT_ARGB32, RawPixel(extents.width).CP(scale), RawPixel(extents.height).CP(scale));
319
cairo_surface_set_device_scale(cg.GetSurface(), scale, scale);
281
320
cairo_t* cr = cg.GetInternalContext();
283
322
gtk_render_background(style_context, cr, 0, 0, extents.width, extents.height);
287
326
warning_tooltip_ = texture_ptr_from_cairo_graphics(cg);
290
void TextInput::OnFontChanged(GtkSettings* settings, GParamSpec* pspec)
329
void TextInput::OnFontChanged()
292
331
glib::String font_name;
293
332
PangoFontDescription* desc;
295
g_object_get(settings, "gtk-font-name", &font_name, NULL);
334
g_object_get(gtk_settings_get_default(), "gtk-font-name", &font_name, NULL);
297
336
desc = pango_font_description_from_string(font_name.Value());
300
339
pango_entry_->SetFontFamily(pango_font_description_get_family(desc));
301
pango_entry_->SetFontSize(PANGO_ENTRY_FONT_SIZE);
302
340
pango_entry_->SetFontOptions(gdk_screen_get_font_options(gdk_screen_get_default()));
304
343
if (hint_font_name() == HINT_LABEL_DEFAULT_FONT_NAME)
306
345
std::ostringstream font_desc;
307
346
font_desc << pango_font_description_get_family(desc) << " " << hint_font_size();
308
347
hint_->SetFont(font_desc.str().c_str());
309
pango_font_description_free(desc);
350
pango_font_description_free(desc);
356
396
layout_->ProcessDraw(GfxContext, force_draw);
358
if (caps_lock_on && mouse_over_warning_icon_)
359
PaintWarningTooltip(GfxContext);
398
if (caps_lock_on && warning_->IsMouseInside() && !tooltip_timeout_)
399
PaintWarningTooltip(GfxContext);
361
401
if (!IsFullRedraw())
373
413
void TextInput::PaintWarningTooltip(nux::GraphicsEngine& graphics_engine)
375
nux::Geometry warning_geo = warning_->GetGeometry();
377
nux::Geometry tooltip_geo = {warning_geo.x - (warning_tooltip_->GetWidth() + TOOLTIP_OFFSET / 2),
378
warning_geo.y - TOOLTIP_Y_OFFSET,
415
nux::Geometry const& warning_geo = warning_->GetGeometry();
417
if (!warning_tooltip_.IsValid())
418
LoadWarningTooltip();
420
nux::Geometry tooltip_geo = {warning_geo.x - (warning_tooltip_->GetWidth() + TOOLTIP_OFFSET.CP(scale) / 2),
421
warning_geo.y - TOOLTIP_Y_OFFSET.CP(scale),
379
422
warning_tooltip_->GetWidth(),
380
423
warning_tooltip_->GetHeight()};
382
nux::GetPainter().PushDrawLayer(graphics_engine, tooltip_geo, CreateWarningLayer(warning_tooltip_.GetPointer()));
425
auto const& warning_layer = CreateWarningLayer(warning_tooltip_.GetPointer());
426
nux::GetPainter().PushDrawLayer(graphics_engine, tooltip_geo, warning_layer.get());
385
429
void TextInput::UpdateBackground(bool force)
388
431
nux::Geometry geo(GetGeometry());
390
LOG_DEBUG(logger) << "height: "
391
<< geo.height << " - "
392
<< layout_->GetGeometry().height << " - "
393
<< pango_entry_->GetGeometry().height;
395
if (geo.width == last_width_
396
&& geo.height == last_height_
433
if (geo.width == last_width_ && geo.height == last_height_ && !force)
400
436
last_width_ = geo.width;
401
437
last_height_ = geo.height;
403
439
nux::CairoGraphics cairo_graphics(CAIRO_FORMAT_ARGB32, last_width_, last_height_);
440
cairo_surface_set_device_scale(cairo_graphics.GetSurface(), scale, scale);
404
441
cairo_t* cr = cairo_graphics.GetInternalContext();
406
443
cairo_graphics.DrawRoundedRectangle(cr,
410
last_width_ - 1, last_height_ - 1,
447
(last_width_/scale) - 1, (last_height_/scale) - 1,
413
450
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
417
454
cairo_set_source_rgba(cr, 1.0f, 1.0f, 1.0f, 0.7f);
418
455
cairo_stroke(cr);
420
nux::BaseTexture* texture2D = texture_from_cairo_graphics(cairo_graphics);
457
auto texture2D = texture_ptr_from_cairo_graphics(cairo_graphics);
422
459
nux::TexCoordXForm texxform;
423
460
texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD);