1// Aseprite
2// Copyright (C) 2020-2022 Igara Studio S.A.
3// Copyright (C) 2017 David Capello
4//
5// This program is distributed under the terms of
6// the End-User License Agreement for Aseprite.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "app/ui/slider2.h"
13
14#include "app/ui/skin/skin_property.h"
15#include "ui/manager.h"
16#include "ui/message.h"
17
18namespace app {
19
20// TODO merge this code with ColorEntry in color_sliders.cpp
21Slider2::Slider2Entry::Slider2Entry(ui::Slider* slider)
22 : ui::Entry(4, "0")
23 , m_slider(slider)
24 , m_recentFocus(false)
25{
26}
27
28bool Slider2::Slider2Entry::onProcessMessage(ui::Message* msg)
29{
30 switch (msg->type()) {
31
32 case ui::kFocusEnterMessage:
33 m_recentFocus = true;
34 break;
35
36 case ui::kKeyDownMessage:
37 if (ui::Entry::onProcessMessage(msg))
38 return true;
39
40 if (hasFocus()) {
41 int scancode = static_cast<ui::KeyMessage*>(msg)->scancode();
42
43 switch (scancode) {
44 // Enter just remove the focus
45 case ui::kKeyEnter:
46 case ui::kKeyEnterPad:
47 releaseFocus();
48 return true;
49
50 case ui::kKeyDown:
51 case ui::kKeyUp: {
52 int value = textInt();
53 if (scancode == ui::kKeyDown)
54 --value;
55 else
56 ++value;
57
58 setTextf("%d", std::clamp(value, minValue(), maxValue()));
59 selectAllText();
60
61 onChange();
62 return true;
63 }
64 }
65
66 // Process focus movement key here because if our
67 // CustomizedGuiManager catches this kKeyDownMessage it
68 // will process it as a shortcut to switch the Timeline.
69 //
70 // Note: The default ui::Manager handles focus movement
71 // shortcuts only for foreground windows.
72 // TODO maybe that should change
73 if (hasFocus() &&
74 manager()->processFocusMovementMessage(msg))
75 return true;
76 }
77 return false;
78 }
79
80 bool result = Entry::onProcessMessage(msg);
81
82 if (msg->type() == ui::kMouseDownMessage && m_recentFocus) {
83 m_recentFocus = false;
84 selectAllText();
85 }
86
87 return result;
88}
89
90Slider2::Slider2(int min, int max, int value)
91 : m_slider(min, max, value)
92 , m_entry(&m_slider)
93{
94 m_slider.setExpansive(true);
95 m_slider.setSizeHint(gfx::Size(128, 0));
96 skin::get_skin_property(&m_entry)->setLook(skin::MiniLook);
97
98 m_slider.Change.connect([this]{ onSliderChange(); });
99 m_entry.Change.connect([this]{ onEntryChange(); });
100
101 addChild(&m_slider);
102 addChild(&m_entry);
103}
104
105void Slider2::onChange()
106{
107 Change();
108}
109
110void Slider2::onSliderChange()
111{
112 m_entry.setTextf("%d", m_slider.getValue());
113 if (m_entry.hasFocus())
114 m_entry.selectAllText();
115 onChange();
116}
117
118void Slider2::onEntryChange()
119{
120 int v = m_entry.textInt();
121 v = std::clamp(v, m_slider.getMinValue(), m_slider.getMaxValue());
122 m_slider.setValue(v);
123
124 onChange();
125}
126
127} // namespace app
128