1 | //============================================================================ |
2 | // |
3 | // SSSS tt lll lll |
4 | // SS SS tt ll ll |
5 | // SS tttttt eeee ll ll aaaa |
6 | // SSSS tt ee ee ll ll aa |
7 | // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" |
8 | // SS SS tt ee ll ll aa aa |
9 | // SSSS ttt eeeee llll llll aaaaa |
10 | // |
11 | // Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony |
12 | // and the Stella Team |
13 | // |
14 | // See the file "License.txt" for information on usage and redistribution of |
15 | // this file, and for a DISCLAIMER OF ALL WARRANTIES. |
16 | //============================================================================ |
17 | |
18 | #include "bspf.hxx" |
19 | #include "Dialog.hxx" |
20 | #include "DialogContainer.hxx" |
21 | #include "EditTextWidget.hxx" |
22 | #include "GuiObject.hxx" |
23 | #include "OSystem.hxx" |
24 | #include "FrameBuffer.hxx" |
25 | #include "FBSurface.hxx" |
26 | #include "Font.hxx" |
27 | #include "Widget.hxx" |
28 | #include "InputTextDialog.hxx" |
29 | |
30 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
31 | InputTextDialog::InputTextDialog(GuiObject* boss, const GUI::Font& font, |
32 | const StringList& labels, const string& title) |
33 | : Dialog(boss->instance(), boss->parent(), font, title), |
34 | CommandSender(boss), |
35 | myEnableCenter(false), |
36 | myErrorFlag(false), |
37 | myXOrig(0), |
38 | myYOrig(0) |
39 | { |
40 | initialize(font, font, labels); |
41 | } |
42 | |
43 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
44 | InputTextDialog::InputTextDialog(GuiObject* boss, const GUI::Font& lfont, |
45 | const GUI::Font& nfont, |
46 | const StringList& labels, const string& title) |
47 | : Dialog(boss->instance(), boss->parent(), lfont, title), |
48 | CommandSender(boss), |
49 | myEnableCenter(false), |
50 | myErrorFlag(false), |
51 | myXOrig(0), |
52 | myYOrig(0) |
53 | { |
54 | initialize(lfont, nfont, labels); |
55 | } |
56 | |
57 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
58 | void InputTextDialog::initialize(const GUI::Font& lfont, const GUI::Font& nfont, |
59 | const StringList& labels) |
60 | { |
61 | const int fontWidth = lfont.getMaxCharWidth(), |
62 | fontHeight = lfont.getFontHeight(), |
63 | lineHeight = lfont.getLineHeight(); |
64 | uInt32 xpos, ypos, i, lwidth = 0, maxIdx = 0; |
65 | WidgetArray wid; |
66 | |
67 | // Calculate real dimensions |
68 | _w = fontWidth * 41; |
69 | _h = lineHeight * 4 + int(labels.size()) * (lineHeight + 5) + _th; |
70 | |
71 | // Determine longest label |
72 | for(i = 0; i < labels.size(); ++i) |
73 | { |
74 | if(labels[i].length() > lwidth) |
75 | { |
76 | lwidth = int(labels[i].length()); |
77 | maxIdx = i; |
78 | } |
79 | } |
80 | lwidth = lfont.getStringWidth(labels[maxIdx]); |
81 | |
82 | // Create editboxes for all labels |
83 | ypos = lineHeight + _th; |
84 | for(i = 0; i < labels.size(); ++i) |
85 | { |
86 | xpos = 10; |
87 | new StaticTextWidget(this, lfont, xpos, ypos + 2, |
88 | lwidth, fontHeight, |
89 | labels[i], TextAlign::Left); |
90 | |
91 | xpos += lwidth + fontWidth; |
92 | EditTextWidget* w = new EditTextWidget(this, nfont, xpos, ypos, |
93 | _w - xpos - 10, lineHeight, "" ); |
94 | wid.push_back(w); |
95 | |
96 | myInput.push_back(w); |
97 | ypos += lineHeight + 5; |
98 | } |
99 | |
100 | xpos = 10; |
101 | myMessage = new StaticTextWidget(this, lfont, xpos, ypos, _w - 2*xpos, fontHeight, |
102 | "" , TextAlign::Left); |
103 | myMessage->setTextColor(kTextColorEm); |
104 | |
105 | addToFocusList(wid); |
106 | |
107 | // Add OK and Cancel buttons |
108 | wid.clear(); |
109 | addOKCancelBGroup(wid, lfont); |
110 | addBGroupToFocusList(wid); |
111 | } |
112 | |
113 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
114 | void InputTextDialog::show() |
115 | { |
116 | myEnableCenter = true; |
117 | open(); |
118 | } |
119 | |
120 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
121 | void InputTextDialog::show(uInt32 x, uInt32 y, const Common::Rect& bossRect) |
122 | { |
123 | uInt32 scale = instance().frameBuffer().hidpiScaleFactor(); |
124 | myXOrig = bossRect.x() + x * scale; |
125 | myYOrig = bossRect.y() + y * scale; |
126 | |
127 | // Only show dialog if we're inside the visible area |
128 | if(!bossRect.contains(myXOrig, myYOrig)) |
129 | return; |
130 | |
131 | myEnableCenter = false; |
132 | open(); |
133 | } |
134 | |
135 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
136 | void InputTextDialog::center() |
137 | { |
138 | if(!myEnableCenter) |
139 | { |
140 | // First set position according to original coordinates |
141 | surface().setDstPos(myXOrig, myYOrig); |
142 | |
143 | // Now make sure that the entire menu can fit inside the screen bounds |
144 | // If not, we reset its position |
145 | if(!instance().frameBuffer().screenRect().contains( |
146 | myXOrig, myXOrig, surface().dstRect())) |
147 | surface().setDstPos(myXOrig, myYOrig); |
148 | } |
149 | else |
150 | Dialog::center(); |
151 | } |
152 | |
153 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
154 | void InputTextDialog::setMessage(const string& title) |
155 | { |
156 | myMessage->setLabel(title); |
157 | myErrorFlag = true; |
158 | } |
159 | |
160 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
161 | const string& InputTextDialog::getResult(int idx) |
162 | { |
163 | if(uInt32(idx) < myInput.size()) |
164 | return myInput[idx]->getText(); |
165 | else |
166 | return EmptyString; |
167 | } |
168 | |
169 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
170 | void InputTextDialog::setText(const string& str, int idx) |
171 | { |
172 | if(uInt32(idx) < myInput.size()) |
173 | myInput[idx]->setText(str); |
174 | } |
175 | |
176 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
177 | void InputTextDialog::setTextFilter(const EditableWidget::TextFilter& f, int idx) |
178 | { |
179 | if(uInt32(idx) < myInput.size()) |
180 | myInput[idx]->setTextFilter(f); |
181 | } |
182 | |
183 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
184 | void InputTextDialog::setFocus(int idx) |
185 | { |
186 | if(uInt32(idx) < myInput.size()) |
187 | Dialog::setFocus(getFocusList()[idx]); |
188 | } |
189 | |
190 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
191 | void InputTextDialog::handleCommand(CommandSender* sender, int cmd, |
192 | int data, int id) |
193 | { |
194 | switch(cmd) |
195 | { |
196 | case GuiObject::kOKCmd: |
197 | case EditableWidget::kAcceptCmd: |
198 | { |
199 | // Send a signal to the calling class that a selection has been made |
200 | // Since we aren't derived from a widget, we don't have a 'data' or 'id' |
201 | if(myCmd) |
202 | sendCommand(myCmd, 0, 0); |
203 | |
204 | // We don't close, but leave the parent to do it |
205 | // If the data isn't valid, the parent may wait until it is |
206 | break; |
207 | } |
208 | |
209 | case EditableWidget::kChangedCmd: |
210 | // Erase the invalid message once editing is restarted |
211 | if(myErrorFlag) |
212 | { |
213 | myMessage->setLabel("" ); |
214 | myErrorFlag = false; |
215 | } |
216 | break; |
217 | |
218 | case EditableWidget::kCancelCmd: |
219 | Dialog::handleCommand(sender, GuiObject::kCloseCmd, data, id); |
220 | break; |
221 | |
222 | default: |
223 | Dialog::handleCommand(sender, cmd, data, id); |
224 | break; |
225 | } |
226 | } |
227 | |