Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2006-2025 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file MFXTextFieldSearch.cpp
15 : /// @author Pablo Alvarez Lopez
16 : /// @date May 2023
17 : ///
18 : // TextField for search elements
19 : /****************************************************************************/
20 :
21 : #include <utils/common/MsgHandler.h>
22 : #include <utils/gui/windows/GUIAppEnum.h>
23 : #include <utils/gui/images/GUIIconSubSys.h>
24 :
25 : #include "MFXTextFieldSearch.h"
26 :
27 : // =========================================================================
28 : // defines
29 : // =========================================================================
30 :
31 : #define ICON_SPACING 4 // Spacing between icon and label (2 + 2)
32 : #define ICON_SIZE 16
33 :
34 : // ===========================================================================
35 : // FOX callback mapping
36 : // ===========================================================================
37 :
38 : FXDEFMAP(MFXTextFieldSearch) MFXTextFieldSearchMap[] = {
39 : FXMAPFUNC(SEL_PAINT, 0, MFXTextFieldSearch::onPaint),
40 : FXMAPFUNC(SEL_FOCUSIN, 0, MFXTextFieldSearch::onFocusIn),
41 : FXMAPFUNC(SEL_FOCUSOUT, 0, MFXTextFieldSearch::onFocusOut),
42 : FXMAPFUNC(SEL_FOCUS_SELF, 0, MFXTextFieldSearch::onFocusSelf),
43 : FXMAPFUNC(SEL_KEYPRESS, 0, MFXTextFieldSearch::onKeyPress),
44 : };
45 :
46 : // Object implementation
47 0 : FXIMPLEMENT(MFXTextFieldSearch, MFXTextFieldIcon, MFXTextFieldSearchMap, ARRAYNUMBER(MFXTextFieldSearchMap))
48 :
49 : // ===========================================================================
50 : // member method definitions
51 : // ===========================================================================
52 :
53 0 : MFXTextFieldSearch::MFXTextFieldSearch(FXComposite* p, MFXStaticToolTip* staticToolTip, FXObject* tgt, FXSelector sel,
54 0 : FXuint opt, FXint x, FXint y, FXint w, FXint h, FXint pl, FXint pr, FXint pt, FXint pb) :
55 : MFXTextFieldIcon(p, staticToolTip, GUIIcon::SEARCH, tgt, sel, opt, x, y, w, h, pl, pr, pt, pb),
56 0 : myTarget(tgt) {
57 0 : }
58 :
59 :
60 : long
61 0 : MFXTextFieldSearch::onKeyPress(FXObject* obj, FXSelector sel, void* ptr) {
62 0 : MFXTextFieldIcon::onKeyPress(obj, sel, ptr);
63 0 : return myTarget->handle(this, FXSEL(SEL_COMMAND, MID_MTEXTFIELDSEARCH_UPDATED), ptr);
64 : }
65 :
66 :
67 : long
68 0 : MFXTextFieldSearch::onPaint(FXObject*, FXSelector, void* ptr) {
69 : FXEvent* ev = (FXEvent*)ptr;
70 0 : FXDCWindow dc(this, ev);
71 : // Draw frame
72 0 : drawFrame(dc, 0, 0, width, height);
73 : // Gray background if disabled
74 0 : if (isEnabled()) {
75 0 : dc.setForeground(backColor);
76 : } else {
77 0 : dc.setForeground(baseColor);
78 : }
79 : // Draw background
80 0 : dc.fillRectangle(border, border, width - (border << 1), height - (border << 1));
81 : // Draw text, clipped against frame interior
82 0 : dc.setClipRectangle(border, border, width - (border << 1), height - (border << 1));
83 : // continue depending of search string
84 0 : if (hasFocus() || (contents.count() > 0)) {
85 0 : drawTextRange(dc, 0, contents.length());
86 : } else {
87 0 : drawSearchTextRange(dc, 0, TL("Type to search..."));
88 : }
89 : // Draw caret
90 0 : if (flags & FLAG_CARET) {
91 0 : int xx = coord(myCursorPosition) - 1;
92 0 : xx += ICON_SPACING + ICON_SIZE;
93 0 : dc.setForeground(myCursorColor);
94 0 : dc.fillRectangle(xx, padtop + border, 1, height - padbottom - padtop - (border << 1));
95 0 : dc.fillRectangle(xx - 2, padtop + border, 5, 1);
96 0 : dc.fillRectangle(xx - 2, height - border - padbottom - 1, 5, 1);
97 : }
98 : // draw icon
99 0 : dc.drawIcon(myIcon, 3, border + padtop + (height - padbottom - padtop - (border << 1) - ICON_SIZE) / 2);
100 0 : return 1;
101 0 : }
102 :
103 :
104 : long
105 0 : MFXTextFieldSearch::onFocusIn(FXObject* sender, FXSelector sel, void* ptr) {
106 0 : update();
107 0 : return MFXTextFieldIcon::onFocusIn(sender, sel, ptr);
108 : }
109 :
110 :
111 :
112 : long
113 0 : MFXTextFieldSearch::onFocusOut(FXObject* sender, FXSelector sel, void* ptr) {
114 0 : update();
115 0 : return MFXTextFieldIcon::onFocusOut(sender, sel, ptr);
116 : }
117 :
118 :
119 :
120 : long
121 0 : MFXTextFieldSearch::onFocusSelf(FXObject* sender, FXSelector sel, void* ptr) {
122 : //onPaint(sender, sel, ptr);
123 0 : return MFXTextFieldIcon::onFocusSelf(sender, sel, ptr);
124 : }
125 :
126 :
127 0 : MFXTextFieldSearch::MFXTextFieldSearch() :
128 0 : MFXTextFieldIcon() {
129 0 : }
130 :
131 :
132 : void
133 0 : MFXTextFieldSearch::drawSearchTextRange(FXDCWindow& dc, FXint fm, const FXString& searchString) {
134 : FXint xx, yy, cw, hh, ww, si, ei, lx, rx, t;
135 0 : FXint rr = width - border - padright;
136 0 : FXint ll = border + padleft;
137 0 : FXint mm = (ll + rr) / 2;
138 : FXint to = (int)searchString.length();
139 0 : if (to <= fm) {
140 : return;
141 : }
142 0 : dc.setFont(myFont);
143 : // Text color
144 0 : dc.setForeground(FXRGBA(128, 128, 128, 255));
145 : // Height
146 0 : hh = myFont->getFontHeight();
147 : // Text sticks to top of field
148 0 : if (options & JUSTIFY_TOP) {
149 0 : yy = padtop + border;
150 0 : } else if (options & JUSTIFY_BOTTOM) {
151 : // Text sticks to bottom of field
152 0 : yy = height - padbottom - border - hh;
153 : } else {
154 : // Text centered in y
155 0 : yy = border + padtop + (height - padbottom - padtop - (border << 1) - hh) / 2;
156 : }
157 : if (myAnchorPosition < myCursorPosition) {
158 : si = myAnchorPosition;
159 : ei = myCursorPosition;
160 : } else {
161 : si = myCursorPosition;
162 : ei = myAnchorPosition;
163 : }
164 : // Normal mode
165 0 : ww = myFont->getTextWidth(searchString.text(), searchString.length());
166 : // Text sticks to right of field
167 0 : if (options & JUSTIFY_RIGHT) {
168 0 : xx = myShiftAmount + rr - ww;
169 0 : } else if (options & JUSTIFY_LEFT) {
170 : // Text sticks on left of field
171 0 : xx = myShiftAmount + ll;
172 : } else {
173 : // Text centered in field
174 0 : xx = myShiftAmount + mm - ww / 2;
175 : }
176 : // add icon spacing
177 0 : xx += ICON_SPACING + ICON_SIZE;
178 : // Reduce to avoid drawing excessive amounts of text
179 0 : lx = xx + myFont->getTextWidth(&searchString[0], fm);
180 0 : rx = lx + myFont->getTextWidth(&searchString[fm], to - fm);
181 0 : while (fm < to) {
182 0 : t = searchString.inc(fm);
183 0 : cw = myFont->getTextWidth(&searchString[fm], t - fm);
184 0 : if (lx + cw >= 0) {
185 : break;
186 : }
187 : lx += cw;
188 : fm = t;
189 : }
190 0 : while (fm < to) {
191 0 : t = searchString.dec(to);
192 0 : cw = myFont->getTextWidth(&searchString[t], to - t);
193 0 : if (rx - cw < width) {
194 : break;
195 : }
196 : rx -= cw;
197 : to = t;
198 : }
199 : // Adjust selected range
200 : if (si < fm) {
201 : si = fm;
202 : }
203 : if (ei > to) {
204 : ei = to;
205 : }
206 : // draw text
207 0 : xx += myFont->getTextWidth(searchString.text(), fm);
208 0 : yy += myFont->getFontAscent();
209 0 : dc.drawText(xx, yy, &searchString[fm], to - fm);
210 : }
|