1 #ifndef _FunctionEditor_h_
2 #define _FunctionEditor_h_
3 /* FunctionEditor.h
4 *
5 * Copyright (C) 1992-2021 Paul Boersma
6 *
7 * This code is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or (at
10 * your option) any later version.
11 *
12 * This code is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 * See the GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this work. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "Editor.h"
22 #include "Graphics.h"
23 #include "Function.h"
24
25 struct FunctionEditor_picture {
26 /* KEEP IN SYNC WITH PREFS. */
27 bool garnish;
28 };
29
Thing_define(FunctionEditor,Editor)30 Thing_define (FunctionEditor, Editor) {
31 /*
32 Inherited attributes:
33 data: must be a Function.
34 */
35 Function & function() { return * reinterpret_cast <Function *> (& our data); }
36
37 /*
38 Subclasses may change the following attributes,
39 but have to respect the invariants,
40 and have to call FunctionEditor_marksChanged ()
41 immediately after making those changes.
42 Invariants:
43 tmin <= startWindow < endWindow <= tmax;
44 tmin <= startSelection <= endSelection <= tmax;
45 */
46 double tmin, tmax, startWindow, endWindow;
47 double startSelection, endSelection; // markers
48
49 autoGraphics graphics; // used in the expose callback
50 /*
51 The Normalized Device cordinates are in "pixelettes", which are a bit smaller than pixels.
52 The purpose of this is optimal look and feel.
53 The extent to which a pixelette is smaller than a pixel depends on the size of the drawing area:
54 for smaller drawing areas, texts are a bit more cramped in their rectangles
55 than for larger drawing areas.
56 */
57 double width_pxlt, height_pxlt; // size of drawing area in pixelettes
58 double _functionViewerLeft, _functionViewerRight; // location of function viewer in pixelettes
59 double _selectionViewerLeft, _selectionViewerRight; // location of selection viewer in pixelettes
60 void updateGeometry (int width_pixels, int height_pixels) {
61 Graphics_setWsViewport (our graphics.get(), 0.0, width_pixels, 0.0, height_pixels);
62 our width_pxlt = width_pixels + 21; // the +21 means that the horizontal margin becomes a tiny bit larger when the window grows
63 our height_pxlt = height_pixels + 111; // the +111 means that the vertical margins become a bit larger when the window grows
64 Graphics_setWsWindow (our graphics.get(), 0.0, our width_pxlt, 0.0, our height_pxlt);
65 //my viewAllAsPixelettes ();
66 /*
67 Put the function viewer at the left and the selection viewer at the right.
68 */
69 our _functionViewerLeft = 0;
70 our _functionViewerRight = ( our p_showSelectionViewer ? our width_pxlt * (2.0/3.0) : our width_pxlt );
71 our _selectionViewerLeft = our _functionViewerRight;
72 our _selectionViewerRight = our width_pxlt;
73 }
74 bool isInSelectionViewer (double x_pxlt) const {
75 return x_pxlt > our _selectionViewerLeft;
76 }
77 void viewAllAsPixelettes () const {
78 Graphics_setViewport (our graphics.get(), 0.0, our width_pxlt, 0.0, our height_pxlt);
79 Graphics_setWindow (our graphics.get(), 0.0, our width_pxlt, 0.0, our height_pxlt);
80 }
81 void viewFunctionViewerAsPixelettes () const {
82 Graphics_setViewport (our graphics.get(), our _functionViewerLeft, our _functionViewerRight, 0.0, our height_pxlt);
83 Graphics_setWindow (our graphics.get(), our _functionViewerLeft, our _functionViewerRight, 0.0, our height_pxlt);
84 }
85 void viewSelectionViewerAsPixelettes () const {
86 Graphics_setViewport (our graphics.get(), our _selectionViewerLeft, our _selectionViewerRight, 0.0, our height_pxlt);
87 Graphics_setWindow (our graphics.get(), our _selectionViewerLeft, our _selectionViewerRight, 0.0, our height_pxlt);
88 }
89 constexpr static double space = 30.0;
90 constexpr static double MARGIN = 107.0;
91 constexpr static double BOTTOM_MARGIN = 2.0;
92 constexpr static double TOP_MARGIN = 3.0;
93 double dataLeft_pxlt () const { return our _functionViewerLeft + our MARGIN; }
94 double dataRight_pxlt () const { return our _functionViewerRight - our MARGIN; }
95 double dataBottom_pxlt () const { return our BOTTOM_MARGIN + our space * 3; }
96 double dataTop_pxlt () const { return our height_pxlt - (our TOP_MARGIN + our space); }
97 void viewDataAsWorldByFraction () const {
98 Graphics_setViewport (our graphics.get(), our dataLeft_pxlt(), our dataRight_pxlt(), our dataBottom_pxlt(), our dataTop_pxlt());
99 Graphics_setWindow (our graphics.get(), our startWindow, our endWindow, 0.0, 1.0);
100 }
101 void viewTallDataAsWorldByPixelettes () const {
102 Graphics_setViewport (our graphics.get(), our dataLeft_pxlt(), our dataRight_pxlt(), 0.0, our height_pxlt);
103 Graphics_setWindow (our graphics.get(), our startWindow, our endWindow, 0.0, our height_pxlt);
104 }
105 constexpr static double SELECTION_VIEWER_MARGIN = 0.0;
106 void viewInnerSelectionViewerAsFractionByFraction () const {
107 Graphics_setViewport (our graphics.get(), our _selectionViewerLeft + our MARGIN, our _selectionViewerRight - our MARGIN,
108 our BOTTOM_MARGIN + our space * 3, our height_pxlt - (our TOP_MARGIN + our space));
109 Graphics_setViewport (our graphics.get(),
110 our _selectionViewerLeft + our SELECTION_VIEWER_MARGIN, our _selectionViewerRight - our SELECTION_VIEWER_MARGIN,
111 our SELECTION_VIEWER_MARGIN, our height_pxlt - our space - our SELECTION_VIEWER_MARGIN
112 );
113 Graphics_setWindow (our graphics.get(), 0.0, 1.0, 0.0, 1.0);
114 }
115
116 GuiText textArea; // optional text at top
117 bool clickWasModifiedByShiftKey; // information for drag-and-drop and for start of play
118 bool duringPlay, backgroundIsUpToDate;
119 struct FunctionEditor_picture picture;
120
121 /* Private: */
122 GuiDrawingArea drawingArea;
123 GuiScrollBar scrollBar;
124 GuiCheckButton groupButton;
125 GuiObject bottomArea;
126 bool group, enableUpdates;
127 int nrect;
128 struct { double left, right, bottom, top; } rect [8];
129 double marker [1 + 3], playCursor, startZoomHistory, endZoomHistory;
130 int numberOfMarkers;
131
132 void v_destroy () noexcept
133 override;
134 void v_info ()
135 override;
136 void v_createMenus ()
137 override;
138 void v_createMenuItems_file (EditorMenu)
139 override;
140 void v_createMenuItems_query (EditorMenu)
141 override;
142 void v_createChildren ()
143 override;
144 void v_createHelpMenuItems (EditorMenu)
145 override;
146 void v_dataChanged ()
147 override;
148
149 virtual void v_draw () { }
150 virtual bool v_hasSelectionViewer () { return false; }
151 virtual void v_drawSelectionViewer () { }
152 virtual void v_drawRealTimeSelectionViewer (double /* time */) { }
153 virtual void v_prepareDraw () { } // for less flashing
154 virtual conststring32 v_domainName () { return U"time"; }
155 virtual conststring32 v_selectionViewerName () { return U"selection viewer"; }
156 virtual conststring32 v_format_domain () { return U"Time domain:"; }
157 virtual const char *v_format_short () { return u8"%.3f"; }
158 virtual const char *v_format_long () { return u8"%f"; }
159 virtual conststring32 v_format_units_long () { return U"seconds"; }
160 virtual conststring32 v_format_units_short () { return U"s"; }
161 virtual const char *v_format_totalDuration () { return u8"Total duration %f seconds"; }
162 virtual const char *v_format_window () { return u8"Visible part %f seconds"; }
163 virtual const char *v_format_selection () { return u8"%f (%.3f / s)"; }
164 virtual int v_fixedPrecision_long () { return 6; }
165 virtual bool v_hasText () { return false; }
166 virtual void v_play (double /* startTime */, double /* endTime */) { }
167 virtual bool v_mouseInWideDataView (GuiDrawingArea_MouseEvent event, double x_world, double y_fraction);
168 /*
169 Message: "they clicked in the data part of the window, or in the left or right margin."
170 'event' is the mouse event, with still relevant info on phase and modifier keys;
171 'x_world' is the time (or another world unit);
172 'y_fraction' is a value between 0.0 (bottom) and 1.0 (top);
173 Behaviour of structFunctionEditor::v_mouseInWideDataView ():
174 moves the cursor to 'x_world', drags to create a selection, or extends the selection.
175 */
176 virtual void v_clickSelectionViewer (double x_fraction, double y_fraction);
177 virtual int v_playCallback (int phase, double startTime, double endTime, double currentTime);
178 virtual void v_updateText () { }
179 virtual void v_prefs_addFields (EditorCommand) { }
180 virtual void v_prefs_setValues (EditorCommand) { }
181 virtual void v_prefs_getValues (EditorCommand) { }
182 virtual void v_createMenuItems_file_draw (EditorMenu) { }
183 virtual void v_createMenuItems_file_extract (EditorMenu) { }
184 virtual void v_createMenuItems_file_write (EditorMenu) { }
185 virtual void v_createMenuItems_view (EditorMenu);
186 virtual void v_createMenuItems_view_timeDomain (EditorMenu);
187 virtual void v_createMenuItems_view_audio (EditorMenu);
188 virtual void v_highlightSelection (double left, double right, double bottom, double top);
189 virtual double v_getBottomOfSoundArea () { return 0.0; }
190 virtual double v_getBottomOfSoundAndAnalysisArea () { return 0.0; }
191 virtual void v_form_pictureSelection (EditorCommand);
192 virtual void v_ok_pictureSelection (EditorCommand);
193 virtual void v_do_pictureSelection (EditorCommand);
194
195 #include "FunctionEditor_prefs.h"
196 };
197
198 int theFunctionEditor_playCallback (FunctionEditor me, int phase, double startTime, double endTime, double currentTime);
199
200 #define FunctionEditor_UPDATE_NEEDED true
201 #define FunctionEditor_NO_UPDATE_NEEDED false
202
203 void FunctionEditor_init (FunctionEditor me, conststring32 title, Function data);
204 /*
205 Function:
206 creates an Editor with a drawing area, a scroll bar and some buttons.
207 Postconditions:
208 my drawingArea is attached to the form at all sides,
209 my scrollBar only to the bottom, left and right sides.
210 */
211
212 void FunctionEditor_marksChanged (FunctionEditor me, bool needsUpdateGroup);
213 /*
214 Function:
215 update optional text field, the scroll bar, the drawing area and the buttons,
216 from the current total time, window, cursor, and selection,
217 and redraw the contents.
218 If needsUpdateGroup is true, this will be done for all the editors in the group.
219 Usage:
220 call this after a change in any of the markers or in the duration of the data.
221 */
222
223 void FunctionEditor_shift (FunctionEditor me, double shift, bool needsUpdateGroup);
224 /*
225 Function:
226 shift (scroll) the window through time, keeping the window length constant.
227 Usage:
228 call this after a search.
229 */
230
231 void FunctionEditor_scrollToView (FunctionEditor me, double t);
232
233 void FunctionEditor_updateText (FunctionEditor me);
234 /*
235 Function:
236 update the optional text widget.
237 Usage:
238 call this after moving the cursor, if that would have to change the text.
239 The generic FunctionEditor also calls this if one of the other marks have changed.
240 Behaviour:
241 we just call the updateText method, which the inheritor will have to modify,
242 since FunctionEditor::updateText does nothing.
243 */
244
245 void FunctionEditor_redraw (FunctionEditor me);
246 /*
247 Function:
248 update the drawing area of a single editor.
249 Usage:
250 call this after she changes a view option (font, scaling, hide/show xx)
251 or after any of the data have changed. In the latter case, also call Editor_broadcastChange.
252 Behaviour:
253 we just call Graphics_updateWs (my graphics).
254 */
255
256 void FunctionEditor_enableUpdates (FunctionEditor me, bool enable);
257 /*
258 Function:
259 temporarily disable update event to cause 'draw' messages.
260 Usage:
261 If you call from your 'draw' method functions that may trigger expose events,
262 you should bracket those routines between
263 FunctionEditor_enableUpdates (me, false);
264 and
265 FunctionEditor_enableUpdates (me, true);
266 This may happen if you call an analysis routine which calls Melder_progress.
267 */
268
269 void FunctionEditor_ungroup (Daata data);
270 /*
271 Function:
272 force all editors containing `data` out of the group.
273 Usage:
274 Start cut or paste methods by calling this function,
275 as the grouped editors will not be synchronized
276 after either of those actions. Worse, the selection
277 may get outside the common interval of the editors.
278 */
279
280 /*
281 Some functions to enforce a common look to all function editors.
282 The x axis of the window is supposed to have been set to [my startWindow, my endWindow].
283 Preconditions:
284 default line type, default line width.
285 Postconditions:
286 default line type, default line width, undefined colour, undefined text alignment.
287 */
288 void FunctionEditor_drawRangeMark (FunctionEditor me, double yWC, conststring32 yWC_string, conststring32 units, int verticalAlignment);
289 void FunctionEditor_drawCursorFunctionValue (FunctionEditor me, double yWC, conststring32 yWC_string, conststring32 units);
290 void FunctionEditor_insertCursorFunctionValue (FunctionEditor me, double yWC, conststring32 yWC_string, conststring32 units, double minimum, double maximum);
291 void FunctionEditor_drawHorizontalHair (FunctionEditor me, double yWC, conststring32 yWC_string, conststring32 units);
292 void FunctionEditor_drawGridLine (FunctionEditor me, double yWC);
293
294 void FunctionEditor_garnish (FunctionEditor me); // optionally selection times and selection hairs
295
296 /* End of file FunctionEditor.h */
297 #endif
298