Cosmetics
[opentx.git] / radio / src / gui / 480x272 / model_mixes.cpp
blob0f98dc9d905bee4a81d2fc0229d07a877cd1d02d
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include "opentx.h"
22 #include <stdio.h>
24 void displayMixStatus(uint8_t channel);
26 int getMixesLinesCount()
28 int lastch = -1;
29 uint8_t count = MAX_OUTPUT_CHANNELS;
30 for (int i=0; i<MAX_MIXERS; i++) {
31 bool valid = mixAddress(i)->srcRaw;
32 if (!valid)
33 break;
34 int ch = mixAddress(i)->destCh;
35 if (ch == lastch) {
36 count++;
38 else {
39 lastch = ch;
42 return count;
45 uint8_t getMixesCount()
47 uint8_t count = 0;
48 uint8_t ch ;
50 for (int i=MAX_MIXERS-1; i>=0; i--) {
51 ch = mixAddress(i)->srcRaw;
52 if (ch != 0) {
53 count++;
56 return count;
59 bool reachMixesLimit()
61 if (getMixesCount() >= MAX_MIXERS) {
62 POPUP_WARNING(STR_NOFREEMIXER);
63 return true;
65 return false;
68 void deleteMix(uint8_t idx)
70 pauseMixerCalculations();
71 MixData * mix = mixAddress(idx);
72 memmove(mix, mix+1, (MAX_MIXERS-(idx+1))*sizeof(MixData));
73 memclear(&g_model.mixData[MAX_MIXERS-1], sizeof(MixData));
74 resumeMixerCalculations();
75 storageDirty(EE_MODEL);
78 void insertMix(uint8_t idx)
80 pauseMixerCalculations();
81 MixData * mix = mixAddress(idx);
82 memmove(mix+1, mix, (MAX_MIXERS-(idx+1))*sizeof(MixData));
83 memclear(mix, sizeof(MixData));
84 mix->destCh = s_currCh-1;
85 mix->srcRaw = s_currCh;
86 if (!isSourceAvailable(mix->srcRaw)) {
87 mix->srcRaw = (s_currCh > 4 ? MIXSRC_Rud - 1 + s_currCh : MIXSRC_Rud - 1 + channelOrder(s_currCh));
88 while (!isSourceAvailable(mix->srcRaw)) {
89 mix->srcRaw += 1;
92 mix->weight = 100;
93 resumeMixerCalculations();
94 storageDirty(EE_MODEL);
97 void copyMix(uint8_t idx)
99 pauseMixerCalculations();
100 MixData * mix = mixAddress(idx);
101 memmove(mix+1, mix, (MAX_MIXERS-(idx+1))*sizeof(MixData));
102 resumeMixerCalculations();
103 storageDirty(EE_MODEL);
106 bool swapMixes(uint8_t & idx, uint8_t up)
108 MixData * x, * y;
109 int8_t tgt_idx = (up ? idx-1 : idx+1);
111 x = mixAddress(idx);
113 if (tgt_idx < 0) {
114 if (x->destCh == 0)
115 return false;
116 x->destCh--;
117 return true;
120 if (tgt_idx == MAX_MIXERS) {
121 if (x->destCh == MAX_OUTPUT_CHANNELS-1)
122 return false;
123 x->destCh++;
124 return true;
127 y = mixAddress(tgt_idx);
128 uint8_t destCh = x->destCh;
129 if(!y->srcRaw || destCh != y->destCh) {
130 if (up) {
131 if (destCh>0) x->destCh--;
132 else return false;
134 else {
135 if (destCh<MAX_OUTPUT_CHANNELS-1) x->destCh++;
136 else return false;
138 return true;
141 pauseMixerCalculations();
142 memswap(x, y, sizeof(MixData));
143 resumeMixerCalculations();
145 idx = tgt_idx;
146 return true;
149 enum MixFields {
150 MIX_FIELD_NAME,
151 MIX_FIELD_SOURCE,
152 MIX_FIELD_WEIGHT,
153 MIX_FIELD_OFFSET,
154 MIX_FIELD_TRIM,
155 MIX_FIELD_CURVE,
156 CASE_FLIGHT_MODES(MIX_FIELD_FLIGHT_MODE)
157 MIX_FIELD_SWITCH,
158 MIX_FIELD_WARNING,
159 MIX_FIELD_MLTPX,
160 MIX_FIELD_DELAY_UP,
161 MIX_FIELD_DELAY_DOWN,
162 MIX_FIELD_SLOW_UP,
163 MIX_FIELD_SLOW_DOWN,
164 MIX_FIELD_COUNT
167 void gvarWeightItem(coord_t x, coord_t y, MixData *md, LcdFlags attr, event_t event)
169 u_int8int16_t weight;
170 MD_WEIGHT_TO_UNION(md, weight);
171 weight.word = GVAR_MENU_ITEM(x, y, weight.word, GV_RANGELARGE_WEIGHT_NEG, GV_RANGELARGE_WEIGHT, attr, 0, event);
172 MD_UNION_TO_WEIGHT(weight, md);
175 bool menuModelMixOne(event_t event)
177 MixData * md2 = mixAddress(s_currIdx) ;
179 SUBMENU_WITH_OPTIONS(STR_MIXES, ICON_MODEL_MIXER, MIX_FIELD_COUNT, OPTION_MENU_NO_SCROLLBAR, { 0, 0, 0, 0, 0, 1, CASE_FLIGHT_MODES((MAX_FLIGHT_MODES-1) | NAVIGATION_LINE_BY_LINE) 0 /*, ...*/ });
180 putsChn(50, 3+FH, md2->destCh+1, MENU_TITLE_COLOR);
181 displayMixStatus(md2->destCh);
183 // The separation line between 2 columns
184 lcdDrawSolidVerticalLine(MENU_COLUMN2_X-10, DEFAULT_SCROLLBAR_Y-FH, DEFAULT_SCROLLBAR_H+5, TEXT_COLOR);
186 int8_t sub = menuVerticalPosition;
187 int8_t editMode = s_editMode;
189 for (int k=0; k<2*NUM_BODY_LINES; k++) {
190 coord_t y;
191 if (k > NUM_BODY_LINES) {
192 y = MENU_CONTENT_TOP - FH + (k-NUM_BODY_LINES)*FH;
194 else {
195 y = MENU_CONTENT_TOP - FH + k*FH;
197 int8_t i = k;
199 LcdFlags attr = (sub==i ? (editMode>0 ? BLINK|INVERS : INVERS) : 0);
200 switch(i) {
201 case MIX_FIELD_NAME:
202 lcdDrawText(MENUS_MARGIN_LEFT, y, STR_MIXNAME);
203 editName(MIXES_2ND_COLUMN, y, md2->name, sizeof(md2->name), event, attr);
204 break;
205 case MIX_FIELD_SOURCE:
206 lcdDrawText(MENUS_MARGIN_LEFT, y, STR_SOURCE);
207 drawSource(MIXES_2ND_COLUMN, y, md2->srcRaw, attr);
208 if (attr) CHECK_INCDEC_MODELSOURCE(event, md2->srcRaw, 1, MIXSRC_LAST);
209 break;
210 case MIX_FIELD_WEIGHT:
211 lcdDrawText(MENUS_MARGIN_LEFT, y, STR_WEIGHT);
212 gvarWeightItem(MIXES_2ND_COLUMN, y, md2, attr|LEFT, event);
213 break;
214 case MIX_FIELD_OFFSET:
216 lcdDrawText(MENUS_MARGIN_LEFT, y, STR_OFFSET);
217 u_int8int16_t offset;
218 MD_OFFSET_TO_UNION(md2, offset);
219 offset.word = GVAR_MENU_ITEM(MIXES_2ND_COLUMN, y, offset.word, GV_RANGELARGE_OFFSET_NEG, GV_RANGELARGE_OFFSET, attr|LEFT, 0, event);
220 MD_UNION_TO_OFFSET(offset, md2);
221 #if 0
222 drawOffsetBar(x+MIXES_2ND_COLUMN+22, y, md2);
223 #endif
224 break;
226 case MIX_FIELD_TRIM:
227 lcdDrawText(MENUS_MARGIN_LEFT, y, STR_TRIM);
228 drawCheckBox(MIXES_2ND_COLUMN, y, !md2->carryTrim, attr);
229 if (attr) md2->carryTrim = !checkIncDecModel(event, !md2->carryTrim, 0, 1);
230 break;
231 case MIX_FIELD_CURVE:
232 lcdDrawText(MENUS_MARGIN_LEFT, y, STR_CURVE);
233 editCurveRef(MIXES_2ND_COLUMN, y, md2->curve, event, attr);
234 break;
235 #if defined(FLIGHT_MODES)
236 case MIX_FIELD_FLIGHT_MODE:
237 lcdDrawText(MENUS_MARGIN_LEFT, y, STR_FLMODE);
238 md2->flightModes = editFlightModes(MIXES_2ND_COLUMN, y, event, md2->flightModes, attr);
239 break;
240 #endif
241 case MIX_FIELD_SWITCH:
242 lcdDrawText(MENUS_MARGIN_LEFT, y, STR_SWITCH);
243 md2->swtch = editSwitch(MIXES_2ND_COLUMN, y, md2->swtch, attr, event);
244 break;
245 case MIX_FIELD_WARNING:
246 lcdDrawText(MENUS_MARGIN_LEFT, y, STR_MIXWARNING);
247 if (md2->mixWarn) {
248 lcdDrawNumber(MIXES_2ND_COLUMN, y, md2->mixWarn, attr|LEFT);
250 else {
251 lcdDrawText(MIXES_2ND_COLUMN, y, STR_OFF, attr);
253 if (attr) {
254 CHECK_INCDEC_MODELVAR_ZERO(event, md2->mixWarn, 3);
256 break;
257 case MIX_FIELD_MLTPX:
258 lcdDrawText(MENUS_MARGIN_LEFT, y, STR_MULTPX);
259 md2->mltpx = editChoice(MIXES_2ND_COLUMN, y, STR_VMLTPX, md2->mltpx, 0, 2, attr, event);
260 break;
261 case MIX_FIELD_DELAY_UP:
262 lcdDrawText(MENU_COLUMN2_X+MENUS_MARGIN_LEFT, y, STR_DELAYUP);
263 md2->delayUp = editDelay(MENU_COLUMN2_X, y, event, attr, md2->delayUp);
264 break;
265 case MIX_FIELD_DELAY_DOWN:
266 lcdDrawText(MENU_COLUMN2_X+MENUS_MARGIN_LEFT, y, STR_DELAYDOWN);
267 md2->delayDown = editDelay(MENU_COLUMN2_X, y, event, attr, md2->delayDown);
268 break;
269 case MIX_FIELD_SLOW_UP:
270 lcdDrawText(MENU_COLUMN2_X+MENUS_MARGIN_LEFT, y, STR_SLOWUP);
271 md2->speedUp = editDelay(MENU_COLUMN2_X, y, event, attr, md2->speedUp);
272 break;
273 case MIX_FIELD_SLOW_DOWN:
274 lcdDrawText(MENU_COLUMN2_X+MENUS_MARGIN_LEFT, y, STR_SLOWDOWN);
275 md2->speedDown = editDelay(MENU_COLUMN2_X, y, event, attr, md2->speedDown);
276 break;
280 return true;
283 #define _STR_MAX(x) "/" #x
284 #define STR_MAX(x) _STR_MAX(x)
286 #define MIX_LINE_WEIGHT_POS 105
287 #define MIX_LINE_SRC_POS 120
288 #define MIX_LINE_CURVE_ICON 175
289 #define MIX_LINE_CURVE_POS 195
290 #define MIX_LINE_SWITCH_ICON 260
291 #define MIX_LINE_SWITCH_POS 280
292 #define MIX_LINE_DELAY_SLOW_POS 340
293 #define MIX_LINE_NAME_FM_ICON 370
294 #define MIX_LINE_NAME_FM_POS 390
295 #define MIX_LINE_SELECT_POS 50
296 #define MIX_LINE_SELECT_WIDTH (LCD_W-MIX_LINE_SELECT_POS-15)
297 #define MIX_STATUS_BAR_W 130
298 #define MIX_STATUS_BAR_H 13
299 #define MIX_STATUS_CHAN_BAR MENUS_MARGIN_LEFT + 45
300 #define MIX_STATUS_ICON_MIXER MIX_STATUS_CHAN_BAR + 140
301 #define MIX_STATUS_ICON_TO MIX_STATUS_ICON_MIXER + 20
302 #define MIX_STATUS_ICON_OUTPUT MIX_STATUS_ICON_TO + 35
303 #define MIX_STATUS_OUT_NAME MIX_STATUS_ICON_OUTPUT + 25
304 #define MIX_STATUS_OUT_BAR LCD_W - MENUS_MARGIN_LEFT - MIX_STATUS_BAR_W
306 void lineMixSurround(coord_t y, LcdFlags flags=CURVE_AXIS_COLOR)
308 lcdDrawRect(MIX_LINE_SELECT_POS, y-INVERT_VERT_MARGIN+1, MIX_LINE_SELECT_WIDTH, INVERT_LINE_HEIGHT, 1, s_copyMode == COPY_MODE ? SOLID : DOTTED, flags);
311 void onMixesMenu(const char * result)
313 uint8_t chn = mixAddress(s_currIdx)->destCh + 1;
315 if (result == STR_EDIT) {
316 pushMenu(menuModelMixOne);
318 else if (result == STR_INSERT_BEFORE || result == STR_INSERT_AFTER) {
319 if (!reachMixesLimit()) {
320 s_currCh = chn;
321 if (result == STR_INSERT_AFTER) { s_currIdx++; menuVerticalPosition++; }
322 insertMix(s_currIdx);
323 pushMenu(menuModelMixOne);
326 else if (result == STR_COPY || result == STR_MOVE) {
327 s_copyMode = (result == STR_COPY ? COPY_MODE : MOVE_MODE);
328 s_copySrcIdx = s_currIdx;
329 s_copySrcCh = chn;
330 s_copySrcRow = menuVerticalPosition;
332 else if (result == STR_DELETE) {
333 deleteMix(s_currIdx);
337 void displayMixInfos(coord_t y, MixData *md)
339 if (md->curve.value != 0 ) lcd->drawBitmap(MIX_LINE_CURVE_ICON, y + 2, mixerSetupCurveBitmap);
340 drawCurveRef(MIX_LINE_CURVE_POS, y, md->curve);
342 if (md->swtch) {
343 lcd->drawBitmap(MIX_LINE_SWITCH_ICON, y + 2, mixerSetupSwitchBitmap);
344 drawSwitch(MIX_LINE_SWITCH_POS, y, md->swtch);
348 void displayMixSmallFlightModes(coord_t x, coord_t y, FlightModesType value)
350 for (int i=0; i<MAX_FLIGHT_MODES; i++) {
351 char s[] = " ";
352 s[0] = '0' + i;
353 if (value & (1<<i)) lcd->drawFilledRect(x, y+2, 8, 12 , SOLID, CURVE_AXIS_COLOR);
354 lcdDrawText(x, y, s, SMLSIZE);
355 x += 8;
359 void displayMixLine(coord_t y, MixData *md)
361 if (md->name[0] && md->flightModes) {
362 if (SLOW_BLINK_ON_PHASE) {
363 lcd->drawBitmap(MIX_LINE_NAME_FM_ICON, y + 2, mixerSetupFlightmodeBitmap);
364 displayMixSmallFlightModes(MIX_LINE_NAME_FM_POS, y + 2, md->flightModes);
366 else {
367 lcd->drawBitmap(MIX_LINE_NAME_FM_ICON, y + 2, mixerSetupLabelBitmap);
368 lcdDrawSizedText(MIX_LINE_NAME_FM_POS, y, md->name, sizeof(md->name), ZCHAR);
371 else if (md->name[0]) {
372 lcd->drawBitmap(MIX_LINE_NAME_FM_ICON, y + 2, mixerSetupLabelBitmap);
373 lcdDrawSizedText(MIX_LINE_NAME_FM_POS, y, md->name, sizeof(md->name), ZCHAR);
375 else if (md->flightModes) {
376 lcd->drawBitmap(MIX_LINE_NAME_FM_ICON, y + 2, mixerSetupFlightmodeBitmap);
377 displayMixSmallFlightModes(MIX_LINE_NAME_FM_POS, y + 2, md->flightModes);
379 displayMixInfos(y, md);
382 void displayMixStatus(uint8_t channel)
384 lcdDrawNumber(MENUS_MARGIN_LEFT, MENU_FOOTER_TOP, channel + 1, MENU_TITLE_COLOR, 0, "CH", NULL);
385 drawSingleMixerBar(MIX_STATUS_CHAN_BAR, MENU_FOOTER_TOP + 4, MIX_STATUS_BAR_W, MIX_STATUS_BAR_H, channel);
387 lcd->drawBitmap(MIX_STATUS_ICON_MIXER, MENU_FOOTER_TOP, mixerSetupMixerBitmap);
388 lcd->drawBitmap(MIX_STATUS_ICON_TO, MENU_FOOTER_TOP, mixerSetupToBitmap);
389 lcd->drawBitmap(MIX_STATUS_ICON_OUTPUT, MENU_FOOTER_TOP, mixerSetupOutputBitmap);
391 if (g_model.limitData[channel].name[0] == '\0')
392 lcdDrawNumber(MIX_STATUS_OUT_NAME, MENU_FOOTER_TOP, channel + 1, MENU_TITLE_COLOR, 0, "CH", NULL);
393 else
394 lcdDrawSizedText(MIX_STATUS_OUT_NAME, MENU_FOOTER_TOP, g_model.limitData[channel].name, sizeof(g_model.limitData[channel].name), MENU_TITLE_COLOR | LEFT | ZCHAR);
395 drawSingleOutputBar(MIX_STATUS_OUT_BAR, MENU_FOOTER_TOP + 4, MIX_STATUS_BAR_W, MIX_STATUS_BAR_H, channel);
398 bool menuModelMixAll(event_t event)
400 const BitmapBuffer * mpx_mode[] = {
401 mixerSetupAddBitmap,
402 mixerSetupMultiBitmap,
403 mixerSetupReplaceBitmap
407 uint8_t sub = menuVerticalPosition;
409 if (s_editMode > 0) {
410 s_editMode = 0;
413 uint8_t chn = mixAddress(s_currIdx)->destCh + 1;
415 int linesCount = getMixesLinesCount();
416 SIMPLE_MENU(STR_MIXES, MODEL_ICONS, menuTabModel, MENU_MODEL_MIXES, linesCount);
418 switch (event) {
419 case EVT_ENTRY:
420 case EVT_ENTRY_UP:
421 s_copyMode = 0;
422 s_copyTgtOfs = 0;
423 break;
424 case EVT_KEY_LONG(KEY_EXIT):
425 if (s_copyMode && s_copyTgtOfs == 0) {
426 deleteMix(s_currIdx);
427 killEvents(event);
428 event = 0;
430 // no break
431 case EVT_KEY_BREAK(KEY_EXIT):
432 if (s_copyMode) {
433 if (s_copyTgtOfs) {
434 // cancel the current copy / move operation
435 if (s_copyMode == COPY_MODE) {
436 deleteMix(s_currIdx);
438 else {
439 do {
440 swapMixes(s_currIdx, s_copyTgtOfs > 0);
441 s_copyTgtOfs += (s_copyTgtOfs < 0 ? +1 : -1);
442 } while (s_copyTgtOfs != 0);
443 storageDirty(EE_MODEL);
445 menuVerticalPosition = s_copySrcRow;
446 s_copyTgtOfs = 0;
448 s_copyMode = 0;
449 event = 0;
451 break;
452 case EVT_KEY_BREAK(KEY_ENTER):
453 if ((!s_currCh || (s_copyMode && !s_copyTgtOfs)) && !READ_ONLY()) {
454 s_copyMode = (s_copyMode == COPY_MODE ? MOVE_MODE : COPY_MODE);
455 s_copySrcIdx = s_currIdx;
456 s_copySrcCh = chn;
457 s_copySrcRow = sub;
458 break;
460 // no break
462 case EVT_KEY_LONG(KEY_ENTER):
463 killEvents(event);
464 if (s_copyTgtOfs) {
465 s_copyMode = 0;
466 s_copyTgtOfs = 0;
467 return true;
469 else {
470 if (READ_ONLY()) {
471 if (!s_currCh) {
472 pushMenu(menuModelMixOne);
475 else {
476 if (s_copyMode) s_currCh = 0;
477 if (s_currCh) {
478 if (reachMixesLimit()) break;
479 insertMix(s_currIdx);
480 pushMenu(menuModelMixOne);
481 s_copyMode = 0;
482 return true;
484 else {
485 event = 0;
486 s_copyMode = 0;
487 POPUP_MENU_ADD_ITEM(STR_EDIT);
488 POPUP_MENU_ADD_ITEM(STR_INSERT_BEFORE);
489 POPUP_MENU_ADD_ITEM(STR_INSERT_AFTER);
490 POPUP_MENU_ADD_ITEM(STR_COPY);
491 POPUP_MENU_ADD_ITEM(STR_MOVE);
492 POPUP_MENU_ADD_ITEM(STR_DELETE);
493 POPUP_MENU_START(onMixesMenu);
497 break;
499 case EVT_ROTARY_RIGHT:
500 case EVT_ROTARY_LEFT:
501 if (s_copyMode) {
502 uint8_t next_ofs = (event==EVT_ROTARY_LEFT ? s_copyTgtOfs - 1 : s_copyTgtOfs + 1);
504 if (s_copyTgtOfs==0 && s_copyMode==COPY_MODE) {
505 // insert a mix on the same channel (just above / just below)
506 if (reachMixesLimit()) break;
507 copyMix(s_currIdx);
508 if (event==EVT_ROTARY_RIGHT) s_currIdx++;
509 else if (sub-menuVerticalOffset >= 6) menuVerticalOffset++;
511 else if (next_ofs==0 && s_copyMode==COPY_MODE) {
512 // delete the mix
513 deleteMix(s_currIdx);
514 if (event==EVT_ROTARY_LEFT) s_currIdx--;
516 else {
517 // only swap the mix with its neighbor
518 if (!swapMixes(s_currIdx, event==EVT_ROTARY_LEFT)) break;
519 storageDirty(EE_MODEL);
522 s_copyTgtOfs = next_ofs;
524 break;
527 char str[6];
528 strAppendUnsigned(strAppend(strAppendUnsigned(str, getMixesCount()), "/"), MAX_MIXERS, 2);
529 lcdDrawText(MENU_TITLE_NEXT_POS, MENU_TITLE_TOP+1, str, HEADER_COLOR);
531 sub = menuVerticalPosition;
532 s_currCh = 0;
533 int cur = 0;
534 int i = 0;
536 for (int ch=1; ch<=MAX_OUTPUT_CHANNELS; ch++) {
537 MixData * md;
538 coord_t y = MENU_CONTENT_TOP + (cur-menuVerticalOffset)*FH;
539 if (i<MAX_MIXERS && (md=mixAddress(i))->srcRaw && md->destCh+1 == ch) {
540 if (cur-menuVerticalOffset >= 0 && cur-menuVerticalOffset < NUM_BODY_LINES) {
541 putsChn(MENUS_MARGIN_LEFT, y, ch, 0); // show CHx
543 uint8_t mixCnt = 0;
544 do {
545 if (s_copyMode) {
546 if (s_copyMode == MOVE_MODE && cur-menuVerticalOffset >= 0 && cur-menuVerticalOffset < NUM_BODY_LINES && s_copySrcCh == ch && s_copyTgtOfs != 0 && i == (s_copySrcIdx + (s_copyTgtOfs<0))) {
547 lineMixSurround(y);
548 cur++; y+=FH;
550 if (s_currIdx == i) {
551 sub = menuVerticalPosition = cur;
552 s_currCh = ch;
555 else if (sub == cur) {
556 s_currIdx = i;
557 displayMixStatus(ch - 1);
559 if (cur-menuVerticalOffset >= 0 && cur-menuVerticalOffset < NUM_BODY_LINES) {
560 LcdFlags attr = ((s_copyMode || sub != cur) ? 0 : INVERS);
562 if (mixCnt > 0) {
563 lcd->drawBitmap(10, y, mpx_mode[md->mltpx]);
566 drawSource(MIX_LINE_SRC_POS, y, md->srcRaw);
568 if (mixCnt == 0 && md->mltpx == 1)
569 lcdDrawText(MIX_LINE_WEIGHT_POS, y, "MULT!", RIGHT | attr | (isMixActive(i) ? BOLD : 0));
570 else
571 gvarWeightItem(MIX_LINE_WEIGHT_POS, y, md, RIGHT | attr | (isMixActive(i) ? BOLD : 0), event);
573 displayMixLine(y, md);
575 BitmapBuffer *delayslowbmp[] = {mixerSetupSlowBitmap, mixerSetupDelayBitmap, mixerSetupDelaySlowBitmap};
576 uint8_t delayslow = 0;
577 if (md->speedDown || md->speedUp)
578 delayslow = 1;
579 if (md->delayUp || md->delayDown)
580 delayslow += 2;
581 if (delayslow)
582 lcd->drawBitmap(MIX_LINE_DELAY_SLOW_POS, y + 2, delayslowbmp[delayslow - 1]);
584 if (s_copyMode) {
585 if ((s_copyMode==COPY_MODE || s_copyTgtOfs == 0) && s_copySrcCh == ch && i == (s_copySrcIdx + (s_copyTgtOfs<0))) {
586 /* draw a border around the raw on selection mode (copy/move) */
587 lineMixSurround(y);
589 if (cur == sub) {
590 /* invert the raw when it's the current one */
591 lineMixSurround(y, ALARM_COLOR);
595 cur++; y+=FH; mixCnt++; i++; md++;
596 } while (i<MAX_MIXERS && md->srcRaw && md->destCh+1 == ch);
597 if (s_copyMode == MOVE_MODE && cur-menuVerticalOffset >= 0 && cur-menuVerticalOffset < NUM_BODY_LINES && s_copySrcCh == ch && i == (s_copySrcIdx + (s_copyTgtOfs<0))) {
598 lineMixSurround(y);
599 cur++; y+=FH;
602 else {
603 uint8_t attr = 0;
604 if (sub == cur) {
605 s_currIdx = i;
606 s_currCh = ch;
607 if (!s_copyMode) {
608 attr = INVERS;
611 if (cur-menuVerticalOffset >= 0 && cur-menuVerticalOffset < NUM_BODY_LINES) {
612 putsChn(MENUS_MARGIN_LEFT, y, ch, attr); // show CHx
613 if (s_copyMode == MOVE_MODE && s_copySrcCh == ch) {
614 lineMixSurround(y);
617 cur++; y+=FH;
621 if (sub >= linesCount-1) menuVerticalPosition = linesCount-1;
623 return true;