• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gansm / finalcut / #760

06 Feb 2026 01:45AM UTC coverage: 69.064% (-0.02%) from 69.083%
#760

push

travis-ci

gansm
Reduce pointer arithmetic and use safe iterators more often

206 of 432 new or added lines in 27 files covered. (47.69%)

25 existing lines in 6 files now uncovered.

37622 of 54474 relevant lines covered (69.06%)

243.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

66.23
/final/fwidget.cpp
1
/***********************************************************************
2
* fwidget.cpp - Intermediate base class for all widget objects         *
3
*                                                                      *
4
* This file is part of the FINAL CUT widget toolkit                    *
5
*                                                                      *
6
* Copyright 2015-2026 Markus Gans                                      *
7
*                                                                      *
8
* FINAL CUT is free software; you can redistribute it and/or modify    *
9
* it under the terms of the GNU Lesser General Public License as       *
10
* published by the Free Software Foundation; either version 3 of       *
11
* the License, or (at your option) any later version.                  *
12
*                                                                      *
13
* FINAL CUT is distributed in the hope that it will be useful, but     *
14
* WITHOUT ANY WARRANTY; without even the implied warranty of           *
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
16
* GNU Lesser General Public License for more details.                  *
17
*                                                                      *
18
* You should have received a copy of the GNU Lesser General Public     *
19
* License along with this program.  If not, see                        *
20
* <http://www.gnu.org/licenses/>.                                      *
21
***********************************************************************/
22

23
#include <algorithm>
24
#include <vector>
25

26
#include "final/fapplication.h"
27
#include "final/fevent.h"
28
#include "final/fstartoptions.h"
29
#include "final/fwidgetcolors.h"
30
#include "final/fwidget.h"
31
#include "final/menu/fmenubar.h"
32
#include "final/output/tty/ftermdata.h"
33
#include "final/util/flog.h"
34
#include "final/util/fstring.h"
35
#include "final/widget/fstatusbar.h"
36
#include "final/widget/fwindow.h"
37

38
namespace finalcut
39
{
40

41
namespace internal
42
{
43

44
struct var
45
{
46
  static FWidget* root_widget;  // global FWidget object
47
};
48

49
FWidget* var::root_widget{nullptr};
50

51
}  // namespace internal
52

53
// static class attributes
54
FStatusBar*           FWidget::statusbar{nullptr};
55
FMenuBar*             FWidget::menubar{nullptr};
56
FWidget*              FWidget::first_shown_widget{nullptr};
57
FWidget*              FWidget::redraw_root_widget{nullptr};
58
FWidget::FWidgetList* FWidget::dialog_list{nullptr};
59
FWidget::FWidgetList* FWidget::always_on_top_list{nullptr};
60
FWidget::FWidgetList* FWidget::close_widget_list{nullptr};
61
bool                  FWidget::dont_raise_window{false};
62
bool                  FWidget::init_terminal{false};
63
bool                  FWidget::init_desktop{false};
64
uInt                  FWidget::modal_dialog_counter{};
65

66
//----------------------------------------------------------------------
67
// class FWidget
68
//----------------------------------------------------------------------
69

70
// constructors and destructor
71
//----------------------------------------------------------------------
72
FWidget::FWidget (FWidget* parent)
46✔
73
  : FObject{parent}
46✔
74
{
75
  // init bit field with 0
76
  memset (&flags.feature, 0, sizeof(flags.feature));
46✔
77
  memset (&flags.visibility, 0, sizeof(flags.visibility));
46✔
78
  memset (&flags.focus, 0, sizeof(flags.focus));
46✔
79
  memset (&flags.shadow, 0, sizeof(flags.shadow));
46✔
80
  memset (&flags.type, 0, sizeof(flags.type));
46✔
81

82
  flags.feature.active = true;             // Enable widget by default
46✔
83
  flags.visibility.visible = true;         // A widget is visible by default
46✔
84
  flags.focus.focusable = true;            // A widget is focusable by default
46✔
85
  flags.visibility.visible_cursor = true;  // A widget has a visible cursor by default
46✔
86
  setWidgetProperty (true);                // This FObject is a widget
46✔
87

88
  if ( ! parent )
46✔
89
  {
90
    if ( internal::var::root_widget )
21✔
91
    {
92
      setExitMessage("FWidget: No parent defined! "
1✔
93
                     "There should be only one root object");
94
      FApplication::exit(EXIT_FAILURE);
1✔
95
      return;
1✔
96
    }
97

98
    initRootWidget();
20✔
99
  }
100
  else
101
  {
102
    woffset = parent->wclient_offset;
25✔
103
  }
104

105
  mapEventFunctions();
45✔
106
  flags.visibility.visible_cursor = false;
45✔
107
  double_flatline_mask.setSize (getWidth(), getHeight());
45✔
108
}
×
109

110
//----------------------------------------------------------------------
111
FWidget::~FWidget()  // destructor
46✔
112
{
113
  processDestroy();
46✔
114
  delCallback();
46✔
115
  removeQueuedEvent();
46✔
116

117
  // unset clicked widget
118
  if ( this == getClickedWidget() )
46✔
119
    setClickedWidget(nullptr);
1✔
120

121
  // unset keyboard widget
122
  if ( this == FApplication::getKeyboardWidget() )
46✔
123
    FApplication::setKeyboardWidget(nullptr);
×
124

125
  // unset the local window widget focus
126
  if ( flags.focus.focus && getMainWidget() != this )
46✔
127
  {
128
    auto window = FWindow::getWindowWidget(this);
2✔
129

130
    if ( window && window != this )
2✔
131
      window->setWindowFocusWidget(nullptr);
1✔
132
  }
133

134
  // unset the global widget focus
135
  if ( this == FWidget::getFocusWidget() )
46✔
136
    FWidget::setFocusWidget(nullptr);
2✔
137

138
  // unset main widget
139
  if ( this == getMainWidget() )
46✔
140
  {
141
    setMainWidget(nullptr);
2✔
142
    quit();
2✔
143
  }
144

145
  accelerator_list.clear();
46✔
146

147
  // finish the program
148
  if ( internal::var::root_widget == this )
46✔
149
    finish();
20✔
150
}
46✔
151

152

153
// public methods of FWidget
154
//----------------------------------------------------------------------
155
auto FWidget::getRootWidget() const -> FWidget*
12✔
156
{
157
  auto obj = static_cast<FWidget*>(getSelf());
12✔
158
  auto p_obj = getParentWidget();
12✔
159

160
  while ( ! obj->isRootWidget() && p_obj )
17✔
161
  {
162
    obj = p_obj;
5✔
163
    p_obj = p_obj->getParentWidget();
5✔
164
  }
165

166
  return obj;
12✔
167
}
168

169
//----------------------------------------------------------------------
170
auto FWidget::getParentWidget() const -> FWidget*
314✔
171
{
172
  auto p_obj = getParent();
314✔
173

174
  if ( p_obj && p_obj->isWidget() )
314✔
175
    return static_cast<FWidget*>(p_obj);
251✔
176

177
  return nullptr;
63✔
178
}
179

180
//----------------------------------------------------------------------
181
auto FWidget::getColorTheme() -> std::shared_ptr<FWidgetColors>&
58✔
182
{
183
  static const auto& color_theme = std::make_unique<std::shared_ptr<FWidgetColors>>();
58✔
184
  return *color_theme;
58✔
185
}
186

187
//----------------------------------------------------------------------
188
auto FWidget::doubleFlatLine_ref (Side side) -> std::vector<bool>&
213✔
189
{
190
  auto& mask = double_flatline_mask;
213✔
191

192
  switch ( side )
213✔
193
  {
194
    case Side::Top:
58✔
195
      return mask.top;
58✔
196

197
    case Side::Right:
48✔
198
      return mask.right;
48✔
199

200
    case Side::Bottom:
58✔
201
      return mask.bottom;
58✔
202

203
    case Side::Left:
48✔
204
      return mask.left;
48✔
205

206
    default:
1✔
207
      throw std::invalid_argument{"Invalid side"};
1✔
208
  }
209
}
210

211
//----------------------------------------------------------------------
212
auto FWidget::getPrintPos() -> FPoint
3✔
213
{
214
  const auto& cur = getPrintCursor();
3✔
215
  return { cur.getX() - woffset.getX1() - getX() + 1
3✔
216
         , cur.getY() - woffset.getY1() - getY() + 1 };
3✔
217
}
218

219
//----------------------------------------------------------------------
220
void FWidget::setMainWidget (FWidget* obj)
4✔
221
{
222
  main_widget = obj;
4✔
223
  auto app_object = FApplication::getApplicationObject();
4✔
224

225
  if ( obj && app_object && ! getFocusWidget() )
4✔
226
  {
227
    dont_raise_window = true;
×
228
    app_object->focusFirstChild();
×
229
    dont_raise_window = false;
×
230
  }
231
}
4✔
232

233
//----------------------------------------------------------------------
234
void FWidget::setVisible (bool enable)
4✔
235
{
236
  flags.visibility.visible = enable;
4✔
237
}
4✔
238

239
//----------------------------------------------------------------------
240
void FWidget::setEnable (bool enable)
6✔
241
{
242
  if ( enable )
6✔
243
    emitCallback("enable");
3✔
244
  else
245
    emitCallback("disable");
3✔
246

247
  flags.feature.active = enable;
6✔
248
}
6✔
249

250
//----------------------------------------------------------------------
251
auto FWidget::setFocus (bool enable, FocusTypes ft) -> bool
82✔
252
{
253
  // Check if the widget is inactive
254
  if ( ! isEnabled() )
82✔
255
    return false;
4✔
256

257
  // The widget already has the focus
258
  if ( hasFocus() == enable )
78✔
259
    return true;
6✔
260

261
  // Set widget focus
262
  if ( enable && ! hasFocus() )
72✔
263
    setFocusOnThisWidget(ft);
37✔
264
  else
265
    flags.focus.focus = false;
35✔
266

267
  // Set status bar text for widget focus
268
  setStatusbarText (enable);
72✔
269
  return enable;
72✔
270
}
271

272
//----------------------------------------------------------------------
273
void FWidget::resetColors()
2✔
274
{
275
  if ( ! hasChildren() )
2✔
276
    return;
1✔
277

278
  for (auto* child : getChildren())
2✔
279
  {
280
    if ( child->isWidget() )
1✔
281
    {
282
      auto widget = static_cast<FWidget*>(child);
1✔
283
      widget->resetColors();
1✔
284
    }
285
  }
286
}
287

288
//----------------------------------------------------------------------
289
void FWidget::useParentWidgetColor()
2✔
290
{
291
  const auto& parent_widget = getParentWidget();
2✔
292

293
  if ( parent_widget )
2✔
294
  {
295
    setForegroundColor (parent_widget->getForegroundColor());
1✔
296
    setBackgroundColor (parent_widget->getBackgroundColor());
1✔
297
  }
298
  else  // Fallback
299
  {
300
    const auto& wc_dialog = getColorTheme()->dialog;
1✔
301
    setForegroundColor (wc_dialog.fg);
1✔
302
    setBackgroundColor (wc_dialog.bg);
1✔
303
  }
304

305
  setColor();
2✔
306
}
2✔
307

308
//----------------------------------------------------------------------
309
void FWidget::setColor() const
4✔
310
{
311
  // Changes colors to the widget default colors
312
  setColor (foreground_color, background_color);
4✔
313
}
4✔
314

315
//----------------------------------------------------------------------
316
void FWidget::setX (int x, bool adjust)
4✔
317
{
318
  if ( getX() == x && wsize.getX() == x )
4✔
319
    return;
1✔
320

321
  if ( ! isWindowWidget() )
3✔
322
    x = std::max(x, 1);
1✔
323

324
  wsize.setX(x);
3✔
325
  adjust_wsize.setX(x);
3✔
326

327
  if ( adjust )
3✔
328
    adjustSize();
3✔
329
}
330

331
//----------------------------------------------------------------------
332
void FWidget::setY (int y, bool adjust)
4✔
333
{
334
  if ( getY() == y && wsize.getY() == y )
4✔
335
    return;
1✔
336

337
  if ( ! isWindowWidget() )
3✔
338
    y = std::max(y, 1);
1✔
339

340
  wsize.setY(y);
3✔
341
  adjust_wsize.setY(y);
3✔
342

343
  if ( adjust )
3✔
344
    adjustSize();
3✔
345
}
346

347
//----------------------------------------------------------------------
348
void FWidget::setPos (const FPoint& p, bool adjust)
9✔
349
{
350
  FPoint pos{p};
9✔
351

352
  if ( getX() == pos.getX() && wsize.getX() == pos.getX()
10✔
353
    && getY() == pos.getY() && wsize.getY() == pos.getY() )
10✔
354
  {
355
    return;
1✔
356
  }
357

358
  if ( ! isWindowWidget() )  // A widgets must be inside the client area
8✔
359
  {
360
    pos.setX(std::max(pos.getX(), 1));
6✔
361
    pos.setY(std::max(pos.getY(), 1));
6✔
362
  }
363

364
  wsize.setPos(pos);
8✔
365
  adjust_wsize.setPos(pos);
8✔
366

367
  if ( adjust )
8✔
368
    adjustSize();
3✔
369
}
370

371
//----------------------------------------------------------------------
372
void FWidget::setWidth (std::size_t width, bool adjust)
18✔
373
{
374
  width = std::max ( std::min (width, size_hints.max_width)
18✔
375
                   , size_hints.min_width );
18✔
376

377
  if ( getWidth() == width && wsize.getWidth() == width  )
18✔
378
    return;
11✔
379

380
  // A width can never be narrower than 1 character
381
  width = std::max(width, std::size_t(1));
7✔
382
  // Set the width
383
  wsize.setWidth(width);
7✔
384
  adjust_wsize.setWidth(width);
7✔
385

386
  if ( adjust )
7✔
387
    adjustSize();
7✔
388

389
  double_flatline_mask.setWidth (getWidth());
7✔
390
}
391

392
//----------------------------------------------------------------------
393
void FWidget::setHeight (std::size_t height, bool adjust)
18✔
394
{
395
  height = std::max ( std::min (height, size_hints.max_height)
18✔
396
                    , size_hints.min_height );
18✔
397

398
  if ( getHeight() == height && wsize.getHeight() == height )
18✔
399
    return;
11✔
400

401
  // A height can never be narrower than 1 character
402
  height = std::max(height, std::size_t(1));
7✔
403
  // Set the height
404
  wsize.setHeight(height);
7✔
405
  adjust_wsize.setHeight(height);
7✔
406

407
  if ( adjust )
7✔
408
    adjustSize();
7✔
409

410
  double_flatline_mask.setHeight (getHeight());
7✔
411
}
412

413
//----------------------------------------------------------------------
414
void FWidget::setSize (const FSize& size, bool adjust)
13✔
415
{
416
  std::size_t width = std::max ( std::min (size.getWidth(), size_hints.max_width)
13✔
417
                               , size_hints.min_width );
13✔
418
  std::size_t height = std::max ( std::min (size.getHeight(), size_hints.max_height)
13✔
419
                                , size_hints.min_height );
13✔
420

421
  if ( getWidth() == width && wsize.getWidth() == width
14✔
422
    && getHeight() == height && wsize.getHeight() == height )
14✔
423
    return;
1✔
424

425
  // A width or a height can never be narrower than 1 character
426
  wsize.setSize ( std::max(width, std::size_t(1))
12✔
427
                , std::max(height, std::size_t(1)) );
12✔
428
  adjust_wsize = wsize;
12✔
429
  double_flatline_mask.setSize (getWidth(), getHeight());
12✔
430

431
  if ( adjust )
12✔
432
    adjustSize();
6✔
433
}
434

435
//----------------------------------------------------------------------
436
void FWidget::setTopPadding (int top, bool adjust)
12✔
437
{
438
  if ( padding.top == top )
12✔
439
    return;
4✔
440

441
  padding.top = top;
8✔
442

443
  if ( ! adjust )
8✔
444
    return;
5✔
445

446
  if ( isRootWidget() )
3✔
447
  {
448
    auto r = internal::var::root_widget;
1✔
449
    r->wclient_offset.setY1 (r->padding.top);
1✔
450
    adjustSizeGlobal();
1✔
451
  }
452
  else
453
    adjustSize();
2✔
454
}
455

456
//----------------------------------------------------------------------
457
void FWidget::setLeftPadding (int left, bool adjust)
11✔
458
{
459
  if ( padding.left == left )
11✔
460
    return;
4✔
461

462
  padding.left = left;
7✔
463

464
  if ( ! adjust )
7✔
465
    return;
5✔
466

467
  if ( isRootWidget() )
2✔
468
  {
469
    auto r = internal::var::root_widget;
1✔
470
    r->wclient_offset.setX1 (r->padding.left);
1✔
471
    adjustSizeGlobal();
1✔
472
  }
473
  else
474
    adjustSize();
1✔
475
}
476

477
//----------------------------------------------------------------------
478
void FWidget::setBottomPadding (int bottom, bool adjust)
12✔
479
{
480
  if ( padding.bottom == bottom )
12✔
481
    return;
6✔
482

483
  padding.bottom = bottom;
6✔
484

485
  if ( ! adjust )
6✔
486
    return;
4✔
487

488
  if ( isRootWidget() )
2✔
489
  {
490
    auto r = internal::var::root_widget;
1✔
491
    auto root_height = int(r->getHeight());
1✔
492
    auto root_pb = r->padding.bottom;
1✔
493

494
    if ( root_height > 1 + root_pb )
1✔
495
      r->wclient_offset.setY2 (root_height - 1 - root_pb);
1✔
496

497
    adjustSizeGlobal();
1✔
498
  }
499
  else
500
    adjustSize();
1✔
501
}
502

503
//----------------------------------------------------------------------
504
void FWidget::setRightPadding (int right, bool adjust)
13✔
505
{
506
  if ( padding.right == right )
13✔
507
    return;
3✔
508

509
  padding.right = right;
10✔
510

511
  if ( ! adjust )
10✔
512
    return;
7✔
513

514
  if ( isRootWidget() )
3✔
515
  {
516
    auto r = internal::var::root_widget;
1✔
517
    auto root_width = int(r->getWidth());
1✔
518
    auto root_pr = r->padding.right;
1✔
519

520
    if ( root_width > 1 + root_pr )
1✔
521
      r->wclient_offset.setX2  (root_width - 1 - root_pr);
1✔
522

523
    adjustSizeGlobal();
1✔
524
  }
525
  else
526
    adjustSize();
2✔
527
}
528

529
//----------------------------------------------------------------------
530
void FWidget::setTerminalSize (const FSize& size) const
2✔
531
{
532
  // Set terminal size to width x height
533

534
  if ( ! FVTerm::getFOutput()->allowsTerminalSizeManipulation() )
2✔
535
    return;
1✔
536

537
  internal::var::root_widget->wsize.setRect(FPoint{1, 1}, size);
1✔
538
  internal::var::root_widget->adjust_wsize = internal::var::root_widget->wsize;
1✔
539
  FVTerm::getFOutput()->setTerminalSize(size);
1✔
540
  detectTerminalSize();
1✔
541
}
542

543
//----------------------------------------------------------------------
544
void FWidget::setGeometry (const FPoint& p, const FSize& s, bool adjust)
18✔
545
{
546
  // Sets the geometry of the widget relative to its parent
547

548
  const int x = p.getX();
18✔
549
  const int y = p.getY();
18✔
550
  std::size_t w = std::max ( std::min (s.getWidth(), size_hints.max_width)
18✔
551
                           , size_hints.min_width );
18✔
552
  std::size_t h = std::max ( std::min (s.getHeight(), size_hints.max_height)
18✔
553
                           , size_hints.min_height );
18✔
554

555
  if ( getPos() == p && getWidth() == w && getHeight() == h )
18✔
556
    return;
5✔
557

558
  if ( isWindowWidget() )  // A window widget can be outside
13✔
559
  {
560
    wsize.setX(x);
3✔
561
    wsize.setY(y);
3✔
562
  }
563
  else  // A normal widget must be inside the client area
564
  {
565
    wsize.setX(std::max(x, 1));
10✔
566
    wsize.setY(std::max(y, 1));
10✔
567
  }
568

569
  // A width or a height can never be narrower than 1 character
570
  wsize.setSize ( std::max(w, std::size_t(1u))
13✔
571
                , std::max(h, std::size_t(1u)) );
13✔
572
  adjust_wsize = wsize;
13✔
573
  const int term_x = getTermX();
13✔
574
  const int term_y = getTermY();
13✔
575

576
  wclient_offset.setCoordinates ( term_x - 1 + padding.left
39✔
577
                                , term_y - 1 + padding.top
13✔
578
                                , term_x - 2 + int(getWidth()) - padding.right
13✔
579
                                , term_y - 2 + int(getHeight()) - padding.bottom );
13✔
580

581
  double_flatline_mask.setSize (getWidth(), getHeight());
13✔
582

583
  if ( adjust )
13✔
584
    adjustSize();
9✔
585
}
586

587
//----------------------------------------------------------------------
588
auto FWidget::setCursorPos (const FPoint& pos) -> bool
7✔
589
{
590
  // sets the input cursor position
591

592
  widget_cursor_position.setPoint(pos);
7✔
593

594
  if ( ! flags.focus.focus
14✔
595
    || flags.visibility.hidden
3✔
596
    || isWindowWidget()
3✔
597
    || ! FWindow::getWindowWidget(this) )
10✔
598
    return false;
6✔
599

600
  const auto& area = getPrintArea();
1✔
601

602
  if ( ! area->hasOwner() )
1✔
603
    return false;
×
604

605
  const auto& area_owner = area->getOwner<FVTerm*>();
1✔
606
  const auto& area_widget = static_cast<FWidget*>(area_owner);
1✔
607
  int woffsetX = getTermX() - area_widget->getTermX();
1✔
608
  int woffsetY = getTermY() - area_widget->getTermY();
1✔
609

610
  if ( isChildPrintArea() )
1✔
611
  {
612
    woffsetX += (1 - area_widget->getLeftPadding());
×
613
    woffsetY += (1 - area_widget->getTopPadding());
×
614
  }
615

616
  bool visible = ! isCursorHideable() || flags.visibility.visible_cursor;
1✔
617
  setAreaCursor ( { woffsetX + pos.getX()
2✔
618
                  , woffsetY + pos.getY() }
1✔
619
                , visible
620
                , area );
621
  return true;
1✔
622
}
623

624
//----------------------------------------------------------------------
625
void FWidget::setPrintPos (const FPoint& pos)
2✔
626
{
627
  const FPoint p{ woffset.getX1() + getX() + pos.getX() - 1,
2✔
628
                  woffset.getY1() + getY() + pos.getY() - 1 };
2✔
629
  setCursor(p);
2✔
630
}
2✔
631

632
//----------------------------------------------------------------------
633
void FWidget::setDoubleFlatLine (Side side, bool bit)
5✔
634
{
635
  auto& mask = double_flatline_mask;
5✔
636

637
  switch ( side )
5✔
638
  {
639
    case Side::Top:
1✔
640
      std::fill(mask.top.begin(), mask.top.end(), bit);
1✔
641
      break;
1✔
642

643
    case Side::Right:
1✔
644
      std::fill(mask.right.begin(), mask.right.end(), bit);
1✔
645
      break;
1✔
646

647
    case Side::Bottom:
1✔
648
      std::fill(mask.bottom.begin(), mask.bottom.end(), bit);
1✔
649
      break;
1✔
650

651
    case Side::Left:
1✔
652
      std::fill(mask.left.begin(), mask.left.end(), bit);
1✔
653
      break;
1✔
654

655
    default:
1✔
656
      throw std::invalid_argument{"Invalid side"};
1✔
657
  }
658
}
4✔
659

660
//----------------------------------------------------------------------
661
void FWidget::setDoubleFlatLine (Side side, int pos, bool bit)
18✔
662
{
663
  if ( pos < 1 )
18✔
664
    return;
3✔
665

666
  const auto index = uLong(pos - 1);
15✔
667
  auto& mask = double_flatline_mask;
15✔
668

669
  auto& side_line = [&mask, side] () -> std::vector<bool>&
1✔
670
  {
671
    switch ( side )
15✔
672
    {
673
      case Side::Top:
10✔
674
        return mask.top;
10✔
675

676
      case Side::Right:
1✔
677
        return mask.right;
1✔
678

679
      case Side::Bottom:
2✔
680
        return mask.bottom;
2✔
681

682
      case Side::Left:
1✔
683
        return mask.left;
1✔
684

685
      default:
1✔
686
        throw std::invalid_argument{"Invalid side"};
1✔
687
    }
688
  }();
15✔
689

690
  if ( index < side_line.size() )
14✔
691
    side_line[index] = bit;
14✔
692
}
693

694
//----------------------------------------------------------------------
695
auto FWidget::childWidgetAt (const FPoint& pos) & -> FWidget*
14✔
696
{
697
  if ( ! hasChildren() )
14✔
698
    return nullptr;
6✔
699

700
  for (auto* child : getChildren())
14✔
701
  {
702
    if ( ! child->isWidget() )
8✔
703
      continue;
×
704

705
    auto widget = static_cast<FWidget*>(child);
8✔
706

707
    if ( widget->isEnabled()
8✔
708
      && widget->isShown()
8✔
709
      && ! widget->isWindowWidget()
8✔
710
      && widget->getTermGeometry().contains(pos) )
16✔
711
    {
712
      auto sub_child = widget->childWidgetAt(pos);
2✔
713
      return ( sub_child != nullptr ) ? sub_child : widget;
2✔
714
    }
715
  }
716

717
  return nullptr;
6✔
718
}
719

720
//----------------------------------------------------------------------
721
auto FWidget::numOfFocusableChildren() & -> int
183✔
722
{
723
  if ( ! hasChildren() )
183✔
724
    return 0;
82✔
725

726
  int num{0};
101✔
727

728
  for (const auto* child : getChildren())
420✔
729
  {
730
    if ( child->isWidget() )
319✔
731
    {
732
      const auto& widget = static_cast<const FWidget*>(child);
315✔
733

734
      if ( widget->isEnabled()
315✔
735
        && widget->isShown()
291✔
736
        && widget->acceptFocus()
221✔
737
        && ! widget->isWindowWidget() )
606✔
738
        num++;
159✔
739
    }
740
  }
741

742
  return num;
101✔
743
}
744

745
//----------------------------------------------------------------------
746
auto FWidget::close() -> bool
5✔
747
{
748
  // Sends a close event and quits the application on acceptance
749

750
  FCloseEvent ev(Event::Close);
5✔
751
  FApplication::sendEvent(this, &ev);
5✔
752

753
  if ( ! ev.isAccepted() )
5✔
754
    return false;
1✔
755

756
  if ( this == getMainWidget() )
4✔
757
    quit();
1✔
758
  else
759
  {
760
    hide();
3✔
761

762
    if ( ! flags.visibility.modal && ! isInFWidgetList(close_widget_list, this) )
3✔
763
      close_widget_list->push_back(this);
1✔
764
  }
765

766
  return true;
4✔
767
}
768

769
//----------------------------------------------------------------------
770
void FWidget::addAccelerator (FKey key, FWidget* obj) &
2✔
771
{
772
  // Adding a keyboard accelerator for the given widget
773

774
  auto widget = static_cast<FWidget*>(FWindow::getWindowWidget(obj));
2✔
775
  FAccelerator accel = { key, obj };
2✔
776

777
  if ( ! widget || widget == statusbar || widget == menubar )
2✔
778
    widget = getRootWidget();
2✔
779

780
  if ( widget )
2✔
781
    widget->accelerator_list.push_back(accel);
2✔
782
}
2✔
783

784
//----------------------------------------------------------------------
785
void FWidget::delAccelerator (FWidget* obj) &
6✔
786
{
787
  // Deletes all accelerators of the given widget
788

789
  auto widget = static_cast<FWidget*>(FWindow::getWindowWidget(this));
6✔
790

791
  if ( ! widget || widget == statusbar || widget == menubar )
6✔
792
    widget = getRootWidget();
4✔
793

794
  if ( ! widget || widget->accelerator_list.empty() )
6✔
795
    return;
1✔
796

797
  auto iter = widget->accelerator_list.cbegin();
5✔
798

799
  while ( iter != widget->accelerator_list.cend() )
14✔
800
  {
801
    if ( iter->object == obj )
9✔
802
      iter = widget->accelerator_list.erase(iter);
4✔
803
    else
804
      ++iter;
5✔
805
  }
806
}
807

808
//----------------------------------------------------------------------
809
void FWidget::flushChanges()
×
810
{
811
  // This method can be reimplemented in a subclass
812
  // to handle pending changes
813
}
×
814

815
//----------------------------------------------------------------------
816
void FWidget::redraw()
×
817
{
818
  // Redraw the widget immediately unless it is hidden.
819

820
  if ( ! redraw_root_widget )
×
821
    redraw_root_widget = this;
×
822

823
  if ( isRootWidget() )
×
824
  {
825
    startDrawing();
×
826
    // clean desktop
827
    auto color_theme_term = getColorTheme()->term;
×
828
    setColor (color_theme_term.fg, color_theme_term.bg);
×
829
    clearArea (getVirtualDesktop());
×
830
  }
831
  else if ( ! isShown() )
×
832
    return;
×
833

834
  draw();
×
835

836
  if ( isRootWidget() )
×
837
    drawWindows();
×
838
  else
839
    drawChildren();
×
840

841
  if ( isRootWidget() )
×
842
    finishDrawing();
×
843

844
  if ( redraw_root_widget == this )
×
845
    redraw_root_widget = nullptr;
×
846
}
847

848
//----------------------------------------------------------------------
849
void FWidget::resize()
×
850
{
851
  if ( isRootWidget() )
×
852
  {
853
    // The screen content is now unknown
854
    auto foutput_ptr = FVTerm::getFOutput();
×
855
    foutput_ptr->clearTerminalState();
×
856
    foutput_ptr->clearTerminalAttributes();
×
857
    // Determine the new terminal size
858
    const FRect old_term_geometry {getTermGeometry()};
×
859
    determineDesktopSize();
×
860
    FRect term_geometry {getTermGeometry()};
×
861
    term_geometry.move (-1, -1);
×
862

863
    if ( old_term_geometry.getSize() == term_geometry.getSize() )
×
864
      return;
×
865

866
    resizeVTerm (term_geometry.getSize());
×
867
    resizeArea ({term_geometry, getShadow()}, getVirtualDesktop());
×
868
    startDrawing();  // Avoid flickering - no update during adjustment
×
869
    adjustSizeGlobal();
×
870
    finishDrawing();
×
871
  }
×
872
  else
873
    adjustSize();
×
874

875
  // resize the four double-flatline-masks
876
  double_flatline_mask.setSize (getWidth(), getHeight());
×
877
}
878

879
//----------------------------------------------------------------------
880
void FWidget::show()
×
881
{
882
  // Make the widget visible and draw it
883

884
  if ( ! isViewable() )
×
885
    return;
×
886

887
  initDesktopOnShown();  // Initialize desktop on first call
×
888
  startShow();
×
889
  initWidgetLayout();    // Makes initial layout settings
×
890
  adjustSize();          // Alignment before drawing
×
891
  draw();                // Draw the widget
×
892
  flags.visibility.hidden = false;
×
893
  flags.visibility.shown = true;
×
894
  showChildWidgets();
×
895
  finalizeShow();
×
896

897
  FShowEvent show_ev (Event::Show);
×
898
  FApplication::sendEvent(this, &show_ev);
×
899
}
900

901
//----------------------------------------------------------------------
902
void FWidget::hide()
7✔
903
{
904
  // Hide the widget
905

906
  flags.visibility.hidden = true;
7✔
907

908
  if ( ! isVisible() )
7✔
909
    return;
×
910

911
  flags.visibility.shown = false;
7✔
912

913
  if ( flags.visibility.visible_cursor && FWidget::getFocusWidget() == this )
7✔
914
  {
915
    getPrintArea()->input_cursor_visible = false;
×
916
  }
917

918
  if ( ! isDialogWidget()
7✔
919
    && FWidget::getFocusWidget() == this
7✔
920
    && ! focusPrevChild() )
14✔
921
  {
922
    if ( FWidget::getFocusWidget() )
×
923
      FWidget::getFocusWidget()->unsetFocus();
×
924

925
    FWidget::setFocusWidget(getParentWidget());
×
926
  }
927

928
  FHideEvent hide_ev (Event::Hide);
7✔
929
  FApplication::sendEvent(this, &hide_ev);
7✔
930
}
931

932
//----------------------------------------------------------------------
933
auto FWidget::focusNextChild() -> bool
15✔
934
{
935
  // Focusing the next widget
936

937
  if ( isDialogWidget() || ! hasParent() )
15✔
938
    return false;
2✔
939

940
  const auto& parent = getParentWidget();
13✔
941

942
  if ( ! parent
26✔
943
    || ! parent->hasChildren()
13✔
944
    || parent->numOfFocusableChildren() < 1 )
26✔
945
    return false;
2✔
946

947
  FWidget* next = nullptr;
11✔
948
  static constexpr auto ft = FocusTypes::NextWidget;
949
  auto iter = searchForwardForWidget(parent, this);
11✔
950
  auto iter_of_this_widget = iter;
11✔
951

952
  do  // Search the next focusable widget
953
  {
954
    ++iter;
19✔
955

956
    if ( iter == parent->cend() )
19✔
957
      iter = parent->cbegin();
3✔
958

959
    if ( (*iter)->isWidget() )
19✔
960
      next = static_cast<FWidget*>(*iter);
18✔
961
  } while ( iter != iter_of_this_widget && canReceiveFocus(next) );
19✔
962

963
  // Focus exception handling
964
  if ( iter == iter_of_this_widget && next && next->hasFocus() )
11✔
965
    return sendFailAtChildFocusEvent (parent, ft);
1✔
966

967
  // Change focus to the next widget and return true if successful
968
  return next
969
       ? next->setFocus (true, ft)
10✔
970
       : false;
10✔
971
}
972

973
//----------------------------------------------------------------------
974
auto FWidget::focusPrevChild() -> bool
13✔
975
{
976
  // Focusing the previous widget
977

978
  if ( isDialogWidget() || ! hasParent() )
13✔
979
    return false;
2✔
980

981
  const auto& parent = getParentWidget();
11✔
982

983
  if ( ! parent
22✔
984
    || ! parent->hasChildren()
11✔
985
    || parent->numOfFocusableChildren() < 1 )
22✔
986
    return false;
2✔
987

988
  FWidget* prev{nullptr};
9✔
989
  static constexpr auto ft = FocusTypes::PreviousWidget;
990
  auto iter = searchBackwardsForWidget(parent, this);
9✔
991
  auto iter_of_this_widget = iter;
9✔
992

993
  do  // Search the previous focusable widget
994
  {
995
    ++iter;
17✔
996

997
    if ( iter == parent->crend() )
17✔
998
      iter = parent->crbegin();
2✔
999

1000
    if ( (*iter)->isWidget() )
17✔
1001
      prev = static_cast<FWidget*>(*iter);
16✔
1002
  } while ( iter != iter_of_this_widget && canReceiveFocus(prev) );
17✔
1003

1004
  if ( iter == iter_of_this_widget && prev && prev->hasFocus() )
9✔
1005
    return sendFailAtChildFocusEvent (parent, ft);  // Send event to the parent widget
1✔
1006

1007
  // Change focus to the previous widget and return true if successful
1008
  return prev
1009
       ? prev->setFocus (true, ft)
8✔
1010
       : false;
8✔
1011
}
1012

1013
//----------------------------------------------------------------------
1014
auto FWidget::focusFirstChild() & -> bool
9✔
1015
{
1016
  // Focusing the first child widget
1017

1018
  if ( ! hasChildren() )
9✔
1019
    return false;
1✔
1020

1021
  for (auto* item : getChildren())
27✔
1022
  {
1023
    if ( ! item->isWidget() )  // Skip non-widget elements
24✔
1024
      continue;
1✔
1025

1026
    auto first = static_cast<FWidget*>(item);
23✔
1027

1028
    if ( first->isEnabled()
23✔
1029
      && first->acceptFocus()
13✔
1030
      && ! first->isMenuWidget() )
36✔
1031
    {
1032
      if ( first->numOfChildren() >= 1 && first->focusFirstChild() )
5✔
1033
        return true;
5✔
1034

1035
      // Change focus to the first widget and return true if successful
1036
      return first->setFocus (true, FocusTypes::NextWidget);
5✔
1037
    }
1038
  }
1039

1040
  return false;
3✔
1041
}
1042

1043
//----------------------------------------------------------------------
1044
auto FWidget::focusLastChild() & -> bool
9✔
1045
{
1046
  // Focusing the last child widget
1047

1048
  if ( ! hasChildren() )
9✔
1049
    return false;
1✔
1050

1051
  for ( auto iter = FObject::crbegin();
8✔
1052
        iter != FObject::crend();
27✔
1053
        ++iter )
19✔
1054
  {
1055
    if ( ! (*iter)->isWidget() )  // Skip non-widget elements
24✔
1056
      continue;
1✔
1057

1058
    auto last = static_cast<FWidget*>(*iter);
23✔
1059

1060
    if ( last->isEnabled()
23✔
1061
      && last->acceptFocus()
13✔
1062
      && ! last->isMenuWidget() )
36✔
1063
    {
1064
      if ( last->numOfChildren() >= 1 && last->focusLastChild() )
5✔
1065
        return true;
5✔
1066

1067
      // Change focus to the last widget and return true if successful
1068
      return last->setFocus (true, FocusTypes::PreviousWidget);
5✔
1069
    }
1070
  }
1071

1072
  return false;
3✔
1073
}
1074

1075
//----------------------------------------------------------------------
1076
void FWidget::move (const FPoint& pos)
3✔
1077
{
1078
  wsize.move(pos);
3✔
1079
  adjust_wsize.move(pos);
3✔
1080
}
3✔
1081

1082
//----------------------------------------------------------------------
1083
void FWidget::quit()
3✔
1084
{
1085
  FApplication::exit(EXIT_SUCCESS);
3✔
1086
}
3✔
1087

1088

1089
// protected methods of FWidget
1090
//----------------------------------------------------------------------
1091
auto FWidget::getPrintArea() -> FVTerm::FTermArea*
6✔
1092
{
1093
  // returns the print area of this object
1094

1095
  if ( getCurrentPrintArea() )
6✔
1096
    return getCurrentPrintArea();
×
1097

1098
  FWidget* obj{};
6✔
1099
  FWidget* p_obj = this;
6✔
1100

1101
  do
1102
  {
1103
    obj = p_obj;
12✔
1104
    p_obj = static_cast<FWidget*>(obj->getParent());
12✔
1105
  }
1106
  while ( ! obj->getVWin() && ! obj->getChildPrintArea() && p_obj );
12✔
1107

1108
  if ( obj->getVWin() )
6✔
1109
  {
1110
    setPrintArea (obj->getVWin());
×
1111
    return getCurrentPrintArea();
×
1112
  }
1113

1114
  if ( obj->getChildPrintArea() )
6✔
1115
  {
1116
    setPrintArea (obj->getChildPrintArea());
×
1117
    return getCurrentPrintArea();
×
1118
  }
1119

1120
  return getVirtualDesktop();
6✔
1121
}
1122

1123
//----------------------------------------------------------------------
1124
void FWidget::addPreprocessingHandler ( const FVTerm* instance
×
1125
                                      , FPreprocessingFunction&& function )
1126
{
1127
  if ( ! getCurrentPrintArea() )
×
1128
    FWidget::getPrintArea();
×
1129

1130
  FVTerm::addPreprocessingHandler (instance, std::move(function));
×
1131
}
×
1132

1133
//----------------------------------------------------------------------
1134
void FWidget::delPreprocessingHandler (const FVTerm* instance)
×
1135
{
1136
  if ( ! getCurrentPrintArea() )
×
1137
    FWidget::getPrintArea();
×
1138

1139
  FVTerm::delPreprocessingHandler (instance);
×
1140
}
×
1141

1142
//----------------------------------------------------------------------
1143
auto FWidget::isChildPrintArea() const -> bool
1✔
1144
{
1145
  const auto& p_obj = static_cast<FWidget*>(getParent());
1✔
1146
  return ( p_obj
1✔
1147
        && p_obj->getChildPrintArea()
1✔
1148
        && p_obj->getChildPrintArea() == getCurrentPrintArea() );
2✔
1149
}
1150

1151
//----------------------------------------------------------------------
1152
void FWidget::setStatusBar (FStatusBar* sbar)
×
1153
{
1154
  if ( ! sbar || statusbar == sbar )
×
1155
    return;
×
1156

1157
  delete statusbar;
×
1158
  statusbar = sbar;
×
1159
}
1160

1161
//----------------------------------------------------------------------
1162
void FWidget::setMenuBar (FMenuBar* mbar)
×
1163
{
1164
  if ( ! mbar || menubar == mbar )
×
1165
    return;
×
1166

1167
  delete menubar;
×
1168
  menubar = mbar;
×
1169
}
1170

1171
//----------------------------------------------------------------------
1172
void FWidget::setParentOffset()
×
1173
{
1174
  const auto& p = getParentWidget();
×
1175

1176
  if ( p )
×
1177
    woffset = p->wclient_offset;
×
1178
}
×
1179

1180
//----------------------------------------------------------------------
1181
void FWidget::setTermOffset()
1✔
1182
{
1183
  const auto& r = getRootWidget();
1✔
1184
  const auto w = int(r->getWidth());
1✔
1185
  const auto h = int(r->getHeight());
1✔
1186
  woffset.setCoordinates (0, 0, w - 1, h - 1);
1✔
1187
}
1✔
1188

1189
//----------------------------------------------------------------------
1190
void FWidget::setTermOffsetWithPadding()
×
1191
{
1192
  const auto& r = getRootWidget();
×
1193
  woffset.setCoordinates
1194
  (
×
1195
    r->getLeftPadding(),
1196
    r->getTopPadding(),
1197
    int(r->getWidth()) - 1 - r->getRightPadding(),
×
1198
    int(r->getHeight()) - 1 - r->getBottomPadding()
×
1199
  );
1200
}
×
1201

1202
//----------------------------------------------------------------------
1203
void FWidget::initTerminal()
×
1204
{
1205
  if ( hasParent() || init_terminal )
×
1206
    return;
×
1207

1208
  // Initialize the physical and virtual terminal
1209
  FVTerm::initTerminal();
×
1210

1211
  // Initialize default widget colors (after terminal detection)
1212
  initColorTheme();
×
1213

1214
  // Set default foreground and background color of the desktop/terminal
1215
  auto color_theme_term = getColorTheme()->term;
×
1216
  internal::var::root_widget->foreground_color = color_theme_term.fg;
×
1217
  internal::var::root_widget->background_color = color_theme_term.bg;
×
1218
  resetColors();
×
1219

1220
  // The terminal is now initialized
1221
  init_terminal = true;
×
1222
}
1223

1224
//----------------------------------------------------------------------
1225
void FWidget::initDesktop()
×
1226
{
1227
  if ( hasParent() || init_desktop )
×
1228
    return;
×
1229

1230
  if ( ! init_terminal )
×
1231
    initTerminal();
×
1232

1233
  // Sets the initial screen settings
1234
  FVTerm::getFOutput()->initScreenSettings();
×
1235

1236
  // Initializing vdesktop
1237
  const auto& r = getRootWidget();
×
1238
  setColor(r->getForegroundColor(), r->getBackgroundColor());
×
1239
  clearArea (getVirtualDesktop());
×
1240

1241
  // Destop is now initialized
1242
  init_desktop = true;
×
1243
}
1244

1245
//----------------------------------------------------------------------
1246
void FWidget::initLayout()
×
1247
{
1248
  // This method must be reimplemented in a subclass to automatically
1249
  // set the widget layouts, before the initial drawing on the terminal
1250
}
×
1251

1252
//----------------------------------------------------------------------
1253
void FWidget::adjustSize()
71✔
1254
{
1255
  // Adjust widget size and position
1256
  adjustWidget();
71✔
1257
  adjustSizeWithinArea(adjust_wsize);
71✔
1258

1259
  // Move and shrink in case of lack of space
1260
  if ( ! hasChildPrintArea() )
71✔
1261
    insufficientSpaceAdjust();
71✔
1262

1263
  // Set the size of the client area
1264
  setClientOffset();
71✔
1265

1266
  // Recursively adjusts child widget sizes
1267
  adjustChildWidgetSizes();
71✔
1268
}
71✔
1269

1270
//----------------------------------------------------------------------
1271
void FWidget::adjustSizeGlobal()
4✔
1272
{
1273
  if ( ! isRootWidget() )
4✔
1274
  {
1275
    getRootWidget()->adjustSizeGlobal();
×
1276
    return;
×
1277
  }
1278

1279
  adjustSize();  // Root widget / FApplication object
4✔
1280
  const auto* vterm_win_list = getWindowList();
4✔
1281

1282
  if ( vterm_win_list && ! vterm_win_list->empty() )
4✔
1283
  {
1284
    for (auto&& vterm_obj : *vterm_win_list)
×
1285
      static_cast<FWidget*>(vterm_obj)->adjustSize();
×
1286
  }
1287
}
1288

1289
//----------------------------------------------------------------------
1290
void FWidget::hideArea (const FSize& size)
×
1291
{
1292
  if ( size.isEmpty() )
×
1293
    return;
×
1294

1295
  const auto& parent_widget = getParentWidget();
×
1296

1297
  if ( parent_widget )
×
1298
  {
1299
    FColor fg = parent_widget->getForegroundColor();
×
1300
    FColor bg = parent_widget->getBackgroundColor();
×
1301
    setColor (fg, bg);
×
1302
  }
1303
  else
1304
  {
1305
    auto color_theme_dialog = getColorTheme()->dialog;
×
1306
    FColor fg = color_theme_dialog.fg;
×
1307
    FColor bg = color_theme_dialog.bg;
×
1308
    setColor (fg, bg);
×
1309
  }
1310

1311
  if ( size.getWidth() == 0 )
×
1312
    return;
×
1313

1314
  for (auto y{0}; y < int(size.getHeight()); y++)
×
1315
  {
1316
    print() << FPoint{1, 1 + y} << FString{size.getWidth(), L' '};
×
1317
  }
1318

1319
  flush();
×
1320
}
1321

1322
//----------------------------------------------------------------------
1323
auto FWidget::event (FEvent* ev) -> bool
110✔
1324
{
1325
  auto iter = event_map.find(ev->getType());
110✔
1326

1327
  // If the event type is not found,
1328
  // call the base class event handler
1329
  if ( iter == event_map.end() )
110✔
1330
    return FObject::event(ev);
×
1331

1332
  iter->second(ev);
110✔
1333
  return true;
110✔
1334
}
1335

1336
//----------------------------------------------------------------------
1337
void FWidget::onKeyPress (FKeyEvent*)
×
1338
{
1339
  // This event handler can be reimplemented in a subclass
1340
  // to receive key press events for the widget
1341
}
×
1342

1343
//----------------------------------------------------------------------
1344
void FWidget::onKeyUp (FKeyEvent*)
×
1345
{
1346
  // This event handler can be reimplemented in a subclass
1347
  // to receive key up events for the widget
1348
}
×
1349

1350
//----------------------------------------------------------------------
1351
void FWidget::onKeyDown (FKeyEvent*)
×
1352
{
1353
  // This event handler can be reimplemented in a subclass
1354
  // to receive key down events for the widget
1355
}
×
1356

1357
//----------------------------------------------------------------------
1358
void FWidget::onMouseDown (FMouseEvent*)
×
1359
{
1360
  // This event handler can be reimplemented in a subclass
1361
  // to receive mouse down events for the widget
1362
}
×
1363

1364
//----------------------------------------------------------------------
1365
void FWidget::onMouseUp (FMouseEvent*)
×
1366
{
1367
  // This event handler can be reimplemented in a subclass
1368
  // to receive mouse up events for the widget
1369
}
×
1370

1371
//----------------------------------------------------------------------
1372
void FWidget::onMouseDoubleClick (FMouseEvent*)
×
1373
{
1374
  // This event handler can be reimplemented in a subclass
1375
  // to receive mouse double clicks events for the widget
1376
}
×
1377

1378
//----------------------------------------------------------------------
1379
void FWidget::onWheel (FWheelEvent*)
×
1380
{
1381
  // This event handler can be reimplemented in a subclass
1382
  // to receive mouse wheel events for the widget
1383
}
×
1384

1385
//----------------------------------------------------------------------
1386
void FWidget::onMouseMove (FMouseEvent*)
×
1387
{
1388
  // This event handler can be reimplemented in a subclass
1389
  // to receive mouse move events for the widget
1390
}
×
1391

1392
//----------------------------------------------------------------------
1393
void FWidget::onFocusIn (FFocusEvent*)
×
1394
{
1395
  // This event handler can be reimplemented in a subclass
1396
  // to receive a widget focus event (get focus)
1397

1398
  redraw();  // Redraw widget when it gets the focus
×
1399
}
×
1400

1401
//----------------------------------------------------------------------
1402
void FWidget::onFocusOut (FFocusEvent*)
×
1403
{
1404
  // This event handler can be reimplemented in a subclass
1405
  // to receive a widget focus event (lost focus)
1406

1407
  redraw();  // Redraw widget when focus is lost
×
1408
}
×
1409

1410
//----------------------------------------------------------------------
1411
void FWidget::onChildFocusIn (FFocusEvent*)
×
1412
{
1413
  // This event handler can be reimplemented in a subclass
1414
  // to receive a child widget focus event (get focus)
1415
}
×
1416

1417
//----------------------------------------------------------------------
1418
void FWidget::onChildFocusOut (FFocusEvent*)
×
1419
{
1420
  // This event handler can be reimplemented in a subclass
1421
  // to receive a child widget focus event (lost focus)
1422
}
×
1423

1424
//----------------------------------------------------------------------
1425
void FWidget::onFailAtChildFocus (FFocusEvent*)
×
1426
{
1427
  // This event handler can be reimplemented in a subclass
1428
  // to receive a child widget focus event (focus failure)
1429
}
×
1430

1431
//----------------------------------------------------------------------
1432
void FWidget::onTermFocusIn (FFocusEvent*)
×
1433
{
1434
  // This event handler can be reimplemented in a subclass
1435
  // to receive a terminal focus-in event (terminal get focus)
1436
}
×
1437

1438
//----------------------------------------------------------------------
1439
void FWidget::onTermFocusOut (FFocusEvent*)
×
1440
{
1441
  // This event handler can be reimplemented in a subclass
1442
  // to receive a terminal focus-out event (terminal lost focus)
1443
}
×
1444

1445
//----------------------------------------------------------------------
1446
void FWidget::onAccel (FAccelEvent*)
×
1447
{
1448
  // This event handler can be reimplemented in a subclass to receive
1449
  // an event when an acceleration key is pressed for this widget
1450
}
×
1451

1452
//----------------------------------------------------------------------
1453
void FWidget::onResize (FResizeEvent* ev)
×
1454
{
1455
  // The terminal was resized
1456
  internal::var::root_widget->resize();
×
1457
  internal::var::root_widget->redraw();
×
1458
  ev->accept();
×
1459
}
×
1460

1461
//----------------------------------------------------------------------
1462
void FWidget::onShow (FShowEvent*)
×
1463
{
1464
  // This event handler can be reimplemented in a subclass
1465
  // to receive a widget show event
1466
}
×
1467

1468
//----------------------------------------------------------------------
1469
void FWidget::onHide (FHideEvent*)
7✔
1470
{
1471
  // This event handler can be reimplemented in a subclass
1472
  // to receive a widget hide event
1473
}
7✔
1474

1475
//----------------------------------------------------------------------
1476
void FWidget::onClose (FCloseEvent* ev)
1✔
1477
{
1478
  // This event handler can be reimplemented in a subclass
1479
  // to receive a widget close event
1480
  ev->accept();
1✔
1481
}
1✔
1482

1483

1484
// private methods of FWidget
1485
//----------------------------------------------------------------------
1486
void FWidget::determineDesktopSize()
20✔
1487
{
1488
  // Determine width and height of the terminal
1489

1490
  detectTerminalSize();
20✔
1491
  auto width = getDesktopWidth();
20✔
1492
  auto height = getDesktopHeight();
20✔
1493
  wsize.setRect(1, 1, width, height);
20✔
1494
  adjust_wsize = wsize;
20✔
1495
  woffset.setRect(0, 0, width, height);
20✔
1496
  auto r = internal::var::root_widget;
20✔
1497
  wclient_offset.setRect(r->padding.left, r->padding.top, width, height);
20✔
1498
}
20✔
1499

1500
//----------------------------------------------------------------------
1501
inline void FWidget::mapEventFunctions()
45✔
1502
{
1503
  mapKeyEvents();
45✔
1504
  mapMouseEvents();
45✔
1505
  mapFocusEvents();
45✔
1506
  mapWidgetEvents();
45✔
1507
}
45✔
1508

1509
//----------------------------------------------------------------------
1510
inline void FWidget::mapKeyEvents()
45✔
1511
{
1512
  // Key events
1513

1514
  event_map.insert (
180✔
1515
  {
1516
    { Event::KeyPress,
×
1517
      [this] (FEvent* ev)
×
1518
      {
1519
        KeyPressEvent (static_cast<FKeyEvent*>(ev));
×
1520
      }
×
1521
    },
1522
    { Event::KeyUp,
×
1523
      [this] (FEvent* ev)
×
1524
      {
1525
        onKeyUp (static_cast<FKeyEvent*>(ev));
×
1526
      }
×
1527
    },
1528
    { Event::KeyDown,
×
1529
      [this] (FEvent* ev)
×
1530
      {
1531
        KeyDownEvent(static_cast<FKeyEvent*>(ev));
×
1532
      }
×
1533
    }
1534
  } );
1535
}
90✔
1536

1537
//----------------------------------------------------------------------
1538
inline void FWidget::mapMouseEvents()
45✔
1539
{
1540
  // Mouse events
1541

1542
  event_map.insert (
270✔
1543
  {
1544
    { Event::MouseDown,
×
1545
      [this] (FEvent* ev)
×
1546
      {
1547
        emitCallback("mouse-press");
×
1548
        onMouseDown (static_cast<FMouseEvent*>(ev));
×
1549
      }
×
1550
    },
1551
    { Event::MouseUp,
×
1552
      [this] (FEvent* ev)
×
1553
      {
1554
        emitCallback("mouse-release");
×
1555
        onMouseUp (static_cast<FMouseEvent*>(ev));
×
1556
      }
×
1557
    },
1558
    { Event::MouseDoubleClick,
×
1559
      [this] (FEvent* ev)
×
1560
      {
1561
        onMouseDoubleClick (static_cast<FMouseEvent*>(ev));
×
1562
      }
×
1563
    },
1564
    { Event::MouseWheel,
×
1565
      [this] (FEvent* ev)
×
1566
      {
1567
        emitWheelCallback(static_cast<FWheelEvent*>(ev));
×
1568
        onWheel (static_cast<FWheelEvent*>(ev));
×
1569
      }
×
1570
    },
1571
    { Event::MouseMove,
×
1572
      [this] (FEvent* ev)
×
1573
      {
1574
        emitCallback("mouse-move");
×
1575
        onMouseMove (static_cast<FMouseEvent*>(ev));
×
1576
      }
×
1577
    }
1578
  } );
1579
}
90✔
1580

1581
//----------------------------------------------------------------------
1582
inline void FWidget::mapFocusEvents()
45✔
1583
{
1584
  // Focus events
1585

1586
  event_map.insert (
360✔
1587
  {
1588
    { Event::FocusIn,
×
1589
      [this] (FEvent* ev)
×
1590
      {
1591
        emitCallback("focus-in");
24✔
1592
        onFocusIn (static_cast<FFocusEvent*>(ev));
24✔
1593
      }
24✔
1594
    },
1595
    { Event::FocusOut,
×
1596
      [this] (FEvent* ev)
×
1597
      {
1598
        emitCallback("focus-out");
24✔
1599
        onFocusOut (static_cast<FFocusEvent*>(ev));
24✔
1600
      }
24✔
1601
    },
1602
    { Event::ChildFocusIn,
×
1603
      [this] (FEvent* ev)
×
1604
      {
1605
        onChildFocusIn (static_cast<FFocusEvent*>(ev));
24✔
1606
      }
24✔
1607
    },
1608
    { Event::ChildFocusOut,
×
1609
      [this] (FEvent* ev)
×
1610
      {
1611
        onChildFocusOut (static_cast<FFocusEvent*>(ev));
24✔
1612
      }
24✔
1613
    },
1614
    { Event::FailAtChildFocus,
×
1615
      [this] (FEvent* ev)
×
1616
      {
1617
        onFailAtChildFocus (static_cast<FFocusEvent*>(ev));
2✔
1618
      }
2✔
1619
    },
1620
    { Event::TerminalFocusOut,
×
1621
      [this] (FEvent* ev)
×
1622
      {
1623
        onTermFocusOut (static_cast<FFocusEvent*>(ev));
×
1624
      }
×
1625
    },
1626
    { Event::TerminalFocusIn,
×
1627
      [this] (FEvent* ev)
×
1628
      {
1629
        onTermFocusIn (static_cast<FFocusEvent*>(ev));
×
1630
      }
×
1631
    }
1632
  } );
1633
}
90✔
1634

1635
//----------------------------------------------------------------------
1636
inline void FWidget::mapWidgetEvents()
45✔
1637
{
1638
  // Widget events
1639

1640
  event_map.insert (
270✔
1641
  {
1642
    { Event::Accelerator,
×
1643
      [this] (FEvent* ev)
×
1644
      {
1645
        onAccel (static_cast<FAccelEvent*>(ev));
×
1646
      }
×
1647
    },
1648
    { Event::Resize,
×
1649
      [this] (FEvent* ev)
×
1650
      {
1651
        onResize (static_cast<FResizeEvent*>(ev));
×
1652
      }
×
1653
    },
1654
    { Event::Show,
×
1655
      [this] (FEvent* ev)
×
1656
      {
1657
        onShow (static_cast<FShowEvent*>(ev));
×
1658
      }
×
1659
    },
1660
    { Event::Hide,
×
1661
      [this] (FEvent* ev)
×
1662
      {
1663
        onHide (static_cast<FHideEvent*>(ev));
7✔
1664
      }
7✔
1665
    },
1666
    { Event::Close,
×
1667
      [this] (FEvent* ev)
×
1668
      {
1669
        onClose (static_cast<FCloseEvent*>(ev));
5✔
1670
      }
5✔
1671
    }
1672
  } );
1673
}
90✔
1674

1675
//----------------------------------------------------------------------
1676
void FWidget::initRootWidget()
20✔
1677
{
1678
  try
1679
  {
1680
    // Initialize widget lists
1681
    dialog_list        = new FWidgetList();
20✔
1682
    always_on_top_list = new FWidgetList();
20✔
1683
    close_widget_list  = new FWidgetList();
20✔
1684
  }
1685
  catch (const std::bad_alloc&)
×
1686
  {
1687
    badAllocOutput ("FWidgetList");
×
1688
    return;
×
1689
  }
×
1690

1691
  // Initialize default widget colors
1692
  // (before terminal detection and internal::var::root_widget is set)
1693
  initColorTheme();
20✔
1694

1695
  // Root widget basic initialization
1696
  internal::var::root_widget = this;
20✔
1697
  first_shown_widget = nullptr;
20✔
1698
  redraw_root_widget = nullptr;
20✔
1699
  modal_dialog_counter = 0;
20✔
1700
  statusbar = nullptr;
20✔
1701

1702
  // Determine width and height of the terminal
1703
  determineDesktopSize();
20✔
1704
}
1705

1706
//----------------------------------------------------------------------
1707
void FWidget::initWidgetLayout()
×
1708
{
1709
  initLayout();
×
1710

1711
  if ( ! hasChildren() )
×
1712
    return;
×
1713

1714
  for (auto* child : getChildren())
×
1715
  {
1716
    if ( child->isWidget() )
×
1717
    {
1718
      auto widget = static_cast<FWidget*>(child);
×
1719
      widget->initWidgetLayout();
×
1720
    }
1721
  }
1722
}
1723

1724
//----------------------------------------------------------------------
1725
inline void FWidget::initDesktopOnShown() const
×
1726
{
1727
  // Initialize desktop on first call
1728

1729
  if ( init_desktop || ! internal::var::root_widget )
×
1730
    return;
×
1731

1732
  internal::var::root_widget->initDesktop();
×
1733
}
1734

1735
//----------------------------------------------------------------------
1736
void FWidget::finish()
20✔
1737
{
1738
  delete close_widget_list;
20✔
1739
  close_widget_list = nullptr;
20✔
1740
  delete dialog_list;
20✔
1741
  dialog_list = nullptr;
20✔
1742
  delete always_on_top_list;
20✔
1743
  always_on_top_list = nullptr;
20✔
1744
  internal::var::root_widget = nullptr;
20✔
1745
}
20✔
1746

1747
//----------------------------------------------------------------------
1748
inline void FWidget::startShow()
×
1749
{
1750
  if ( first_shown_widget )
×
1751
    return;
×
1752

1753
  startDrawing();
×
1754
  first_shown_widget = this;
×
1755
}
1756

1757
//----------------------------------------------------------------------
1758
inline void FWidget::finalizeShow() const
×
1759
{
1760
  if ( ! first_shown_widget || first_shown_widget != this )
×
1761
    return ;
×
1762

1763
  finishDrawing();
×
1764
  forceTerminalUpdate();
×
1765
  first_shown_widget = nullptr;
×
1766
}
1767

1768
//----------------------------------------------------------------------
1769
inline void FWidget::showChildWidgets()
×
1770
{
1771
  if ( ! hasChildren() )
×
1772
    return;
×
1773

1774
  for (auto* child : getChildren())
×
1775
  {
1776
    auto child_widget = static_cast<FWidget*>(child);
×
1777

1778
    if ( child->isWidget() && ! child_widget->flags.visibility.hidden )
×
1779
      child_widget->show();
×
1780
  }
1781
}
1782

1783
//----------------------------------------------------------------------
1784
inline void FWidget::moveLeftIfNotEnoughSpace()
37✔
1785
{
1786
  int diff = getTermX() + int(getWidth()) - padding.right - (woffset.getX2() + 2);
37✔
1787

1788
  if ( diff <= 0 )
37✔
1789
    return;
26✔
1790

1791
  adjust_wsize.x1_ref() = std::max(adjust_wsize.getX1() - diff, 1);
11✔
1792
  adjust_wsize.x2_ref() -= diff;
11✔
1793
}
1794

1795
//----------------------------------------------------------------------
1796
inline void FWidget::moveUpIfNotEnoughSpace()
37✔
1797
{
1798
  int diff = getTermY() + int(getHeight()) - padding.bottom - (woffset.getY2() + 2);
37✔
1799

1800
  if ( diff <= 0 )
37✔
1801
    return;
23✔
1802

1803
  adjust_wsize.y1_ref() = std::max(adjust_wsize.getY1() - diff, 1);
14✔
1804
  adjust_wsize.y2_ref() -= diff;
14✔
1805
}
1806

1807
//----------------------------------------------------------------------
1808
inline void FWidget::reduceWidthIfNotEnoughSpace()
37✔
1809
{
1810
  int diff = woffset.getX1() + int(getWidth()) - 1 - woffset.getX2();
37✔
1811
  adjust_wsize.x2_ref() = std::min ( adjust_wsize.getX2() - diff
37✔
1812
                                   , adjust_wsize.getX2() );
37✔
1813

1814
  // Handle the minimum hint value
1815
  adjust_wsize.x2_ref() = adjust_wsize.getX1()
37✔
1816
                        + int(std::max(getWidth(), size_hints.min_width)) - 1;
37✔
1817

1818
  // The minimum with is 1
1819
  adjust_wsize.x2_ref() = adjust_wsize.getX1() + std::max(int(getWidth()), 1) - 1;
37✔
1820
}
37✔
1821

1822
//----------------------------------------------------------------------
1823
inline void FWidget::reduceHeightIfNotEnoughSpace()
37✔
1824
{
1825
  int diff = woffset.getY1() + int(getHeight()) - 1 - woffset.getY2();
37✔
1826
  adjust_wsize.y2_ref() = std::min ( adjust_wsize.getY2() - diff
37✔
1827
                                   , adjust_wsize.getY2() );
37✔
1828

1829
  // Handle the minimum hint value
1830
  adjust_wsize.y2_ref() = adjust_wsize.getY1()
37✔
1831
                        + int(std::max(getHeight(), size_hints.min_height)) - 1;
37✔
1832

1833
  // The minimum with is 1
1834
  adjust_wsize.y2_ref() = adjust_wsize.getY1() + std::max(int(getHeight()), 1) - 1;
37✔
1835
}
37✔
1836

1837
//----------------------------------------------------------------------
1838
inline void FWidget::insufficientSpaceAdjust()
71✔
1839
{
1840
  // Move and shrink widget if there is not enough space available
1841

1842
  if ( isWindowWidget() )
71✔
1843
    return;
34✔
1844

1845
  moveLeftIfNotEnoughSpace();      // move left if not enough space
37✔
1846
  moveUpIfNotEnoughSpace();        // move up if not enough space
37✔
1847
  reduceWidthIfNotEnoughSpace();   // reduce the width if not enough space
37✔
1848
  reduceHeightIfNotEnoughSpace();  // reduce the height if not enough space
37✔
1849
}
1850

1851
//----------------------------------------------------------------------
1852
void FWidget::KeyPressEvent (FKeyEvent* kev)
×
1853
{
1854
  auto change_focus = [this] (const auto& key)
×
1855
  {
1856
    if ( isFocusNextKey(key) )
×
1857
      return focusNextChild();
×
1858

1859
    if ( isFocusPrevKey(key) )
×
1860
      return focusPrevChild();
×
1861

1862
    return false;
×
1863
  };
×
1864

1865
  FWidget* widget(this);
×
1866

1867
  while ( widget )
×
1868
  {
1869
    widget->onKeyPress(kev);
×
1870

1871
    if ( ! kev->isAccepted() && change_focus(kev->key()) )
×
1872
      return;
×
1873

1874
    if ( kev->isAccepted()
×
1875
      || widget->isRootWidget()
×
1876
      || widget->getFlags().visibility.modal )
×
1877
      return;
×
1878

1879
    widget = widget->getParentWidget();
×
1880
  }
1881
}
1882

1883
//----------------------------------------------------------------------
1884
void FWidget::KeyDownEvent (FKeyEvent* kev)
×
1885
{
1886
  FWidget* widget(this);
×
1887

1888
  while ( widget )
×
1889
  {
1890
    widget->onKeyDown(kev);
×
1891

1892
    if ( kev->isAccepted() || widget->isRootWidget() )
×
1893
      break;
×
1894

1895
    widget = widget->getParentWidget();
×
1896
  }
1897
}
×
1898

1899
//----------------------------------------------------------------------
1900
void FWidget::emitWheelCallback (const FWheelEvent* ev) const
×
1901
{
1902
  const auto& wheel = ev->getWheel();
×
1903

1904
  if ( wheel == MouseWheel::Up )
×
1905
    emitCallback("mouse-wheel-up");
×
1906
  else if ( wheel == MouseWheel::Down )
×
1907
    emitCallback("mouse-wheel-down");
×
1908
}
×
1909

1910
//----------------------------------------------------------------------
1911
void FWidget::setWindowFocus (bool enable)
37✔
1912
{
1913
  // Set the focus of the window that contains this FWidget object
1914

1915
  if ( ! enable )
37✔
1916
    return;
×
1917

1918
  // Get the FWindow object that contains this FWidget object
1919
  auto window = FWindow::getWindowWidget(this);
37✔
1920

1921
  if ( ! window )
37✔
1922
    return;
37✔
1923

1924
  if ( ! (window->isWindowActive() || dont_raise_window) )
×
1925
  {
1926
    // Raise the window, set it active and redraw it
1927
    bool has_raised = window->raiseWindow();
×
1928
    FWindow::setActiveWindow(window);
×
1929

1930
    if ( has_raised && window->isVisible() && window->isShown() )
×
1931
      window->redraw();
×
1932
  }
1933

1934
  // set focus widget of this window
1935
  window->setWindowFocusWidget(this);
×
1936
}
1937

1938
//----------------------------------------------------------------------
1939
inline auto FWidget::searchForwardForWidget ( const FWidget* parent
11✔
1940
                                            , const FWidget* widget ) const -> FObjectList::const_iterator
1941
{
1942
  auto iter = parent->cbegin();
11✔
1943
  const auto last = parent->cend();
11✔
1944

1945
  while ( iter != last )  // Search forward for this widget
22✔
1946
  {
1947
    if ( ! (*iter)->isWidget() )  // Skip non-widget elements
22✔
1948
    {
1949
      ++iter;
2✔
1950
      continue;
2✔
1951
    }
1952

1953
    if ( static_cast<FWidget*>(*iter) == widget )
20✔
1954
      break;  // Stop search when we reach this widget
11✔
1955

1956
    ++iter;
9✔
1957
  }
1958

1959
  return iter;
11✔
1960
}
1961

1962
//----------------------------------------------------------------------
1963
inline auto FWidget::searchBackwardsForWidget ( const FWidget* parent
9✔
1964
                                              , const FWidget* widget ) const -> FObjectList::const_reverse_iterator
1965
{
1966
  auto iter = parent->crbegin();
9✔
1967
  const auto first = parent->crend();
9✔
1968

1969
  while ( iter != first )  // Search backwards for this widget
15✔
1970
  {
1971
    if ( ! (*iter)->isWidget() )  // Skip non-widget elements
15✔
1972
    {
1973
      ++iter;
×
1974
      continue;
×
1975
    }
1976

1977
    if ( static_cast<FWidget*>(*iter) == widget )
15✔
1978
      break;  // Stop search when we reach this widget
9✔
1979

1980
    ++iter;
6✔
1981
  }
1982

1983
  return iter;
9✔
1984
}
1985

1986
//----------------------------------------------------------------------
1987
inline auto FWidget::isViewable() const -> bool
×
1988
{
1989
  return isVisible()
×
1990
      && ! isShown()
×
1991
      && ! FApplication::isQuit();
×
1992
}
1993

1994
//----------------------------------------------------------------------
1995
inline auto FWidget::canReceiveFocus (const FWidget* widget) const -> bool
34✔
1996
{
1997
  return ! widget
1998
      || ! widget->isEnabled()
32✔
1999
      || ! widget->acceptFocus()
30✔
2000
      || ! widget->isShown()
26✔
2001
      || widget->isWindowWidget();
66✔
2002
}
2003

2004
//----------------------------------------------------------------------
2005
inline void FWidget::setFocusOnThisWidget (FocusTypes ft)
37✔
2006
{
2007
  auto last_focus = FWidget::getFocusWidget();
37✔
2008

2009
  if ( last_focus )
37✔
2010
  {
2011
    // Unfocus the currently focused widget
2012
    last_focus->unsetFocus();
36✔
2013

2014
    // Send events for this widget
2015
    if ( ! sendFocusOutEvent(last_focus, ft) )
36✔
2016
      return;
×
2017
  }
2018

2019
  // Use this widget for global focus
2020
  FWidget::setFocusWidget(this);
37✔
2021
  flags.focus.focus = true;
37✔
2022

2023
  // Activates the window with the focused widget
2024
  setWindowFocus();
37✔
2025

2026
  // Send events for the follow widget
2027
  sendFocusInEvent(this, ft);
37✔
2028
}
2029

2030
//----------------------------------------------------------------------
2031
inline auto FWidget::sendFailAtChildFocusEvent ( FWidget* widget
2✔
2032
                                               , FocusTypes ft ) const -> bool
2033
{
2034
  if ( ! widget )
2✔
2035
    return false;
×
2036

2037
  // Send event to the given widget
2038
  FFocusEvent ncfc (Event::FailAtChildFocus);
2✔
2039
  ncfc.setFocusType(ft);
2✔
2040
  FApplication::sendEvent(widget, &ncfc);
2✔
2041
  return ncfc.isAccepted();
2✔
2042
}
2043

2044
//----------------------------------------------------------------------
2045
inline auto FWidget::sendFocusOutEvent ( FWidget* widget
36✔
2046
                                       , FocusTypes ft ) const -> bool
2047
{
2048
  if ( ! widget )
36✔
2049
    return false;
×
2050

2051
  // Send event to the focus widget
2052
  FFocusEvent f_out (Event::FocusOut);  // isAccepted() is default
36✔
2053
  f_out.setFocusType(ft);
36✔
2054
  FApplication::sendEvent(widget, &f_out);
36✔
2055

2056
  const auto& parent_widget = getParentWidget();
36✔
2057

2058
  if ( parent_widget )
36✔
2059
  {
2060
    // Send event to parent focus
2061
    FFocusEvent cf_out (Event::ChildFocusOut);
36✔
2062
    cf_out.setFocusType(ft);
36✔
2063
    cf_out.ignore();
36✔
2064
    FApplication::sendEvent(parent_widget, &cf_out);
36✔
2065

2066
    if ( cf_out.isAccepted() )
36✔
2067
      f_out.ignore();
×
2068
  }
2069

2070
  return f_out.isAccepted();
36✔
2071
}
2072

2073
//----------------------------------------------------------------------
2074
inline auto FWidget::sendFocusInEvent ( FWidget* widget
37✔
2075
                                      , FocusTypes ft ) const -> bool
2076
{
2077
  if ( ! widget )
37✔
2078
    return false;
×
2079

2080
  const auto& parent_widget = widget->getParentWidget();
37✔
2081

2082
  if ( parent_widget )
37✔
2083
  {
2084
    // Send event to the parent of the follow widget
2085
    FFocusEvent cf_in (Event::ChildFocusIn);
37✔
2086
    cf_in.setFocusType(ft);
37✔
2087
    FApplication::sendEvent(parent_widget, &cf_in);
37✔
2088
  }
2089

2090
  // Send event to the follow widget
2091
  FFocusEvent f_in (Event::FocusIn);
37✔
2092
  f_in.setFocusType(ft);
37✔
2093
  FApplication::sendEvent(widget, &f_in);
37✔
2094

2095
  return f_in.isAccepted();
37✔
2096
}
2097

2098
//----------------------------------------------------------------------
2099
void FWidget::draw()
×
2100
{
2101
  // This method must be reimplemented in a subclass
2102
  // for drawing the widget
2103
}
×
2104

2105
//----------------------------------------------------------------------
2106
void FWidget::drawWindows() const
×
2107
{
2108
  // Redraw windows
2109
  FChar default_char{};
×
2110
  default_char.ch[0] = L' ';
×
NEW
2111
  default_char.color.pair = {FColor::Default, FColor::Default};
×
2112
  const auto* vterm_win_list = getWindowList();
×
2113

2114
  if ( ! vterm_win_list || vterm_win_list->empty() )
×
2115
    return;
×
2116

2117
  for (auto&& vterm_obj : *vterm_win_list)
×
2118
  {
2119
    const auto win = static_cast<FWidget*>(vterm_obj);
×
2120

2121
    if ( win->isShown() )
×
2122
    {
2123
      auto v_win = win->getVWin();
×
2124
      std::fill (v_win->data.begin(), v_win->data.end(), default_char);
×
2125
      win->redraw();
×
2126
    }
2127
  }
2128
}
2129

2130
//----------------------------------------------------------------------
2131
void FWidget::drawChildren()
×
2132
{
2133
  // Draw child elements
2134
  if ( ! hasChildren() )
×
2135
    return;
×
2136

2137
  for (auto* child : getChildren())
×
2138
  {
2139
    if ( child->isWidget() )
×
2140
    {
2141
      auto widget = static_cast<FWidget*>(child);
×
2142

2143
      if ( widget->isShown() && ! widget->isWindowWidget() )
×
2144
        widget->redraw();
×
2145
    }
2146
  }
2147
}
2148

2149
//----------------------------------------------------------------------
2150
inline void FWidget::adjustWidget()
71✔
2151
{
2152
  if ( isRootWidget() )
71✔
2153
    return;
6✔
2154

2155
  const auto& p = getParentWidget();
65✔
2156

2157
  if ( isWindowWidget() )
65✔
2158
    setWindowOffset();
30✔
2159
  else
2160
    setWidgetOffset(p);
35✔
2161

2162
  adjust_wsize = wsize;
65✔
2163
}
2164

2165
//----------------------------------------------------------------------
2166
inline void FWidget::adjustSizeWithinArea (FRect& box) const
71✔
2167
{
2168
  const FRect uninitialized(FPoint{0, 0}, FPoint{-1, -1});
71✔
2169

2170
  if ( ! init_desktop
142✔
2171
    || ! init_terminal
×
2172
    || isWindowWidget()
×
2173
    || box == uninitialized )
71✔
2174
    return;
71✔
2175

2176
  const auto w = box.getWidth();
×
2177
  const auto h = box.getHeight();
×
2178

2179
  // A width or a height can never be narrower than 1 character
2180
  // and wider than the client width or height of its parent
2181
  box.setSize( std::max(std::min(w, woffset.getWidth()), std::size_t(1u)),
×
2182
               std::max(std::min(h, woffset.getHeight()), std::size_t(1u)) );
×
2183
}
2184

2185
//----------------------------------------------------------------------
2186
inline void FWidget::adjustChildWidgetSizes()
71✔
2187
{
2188
  // This method is called only by adjustSize() and recursively adjusts
2189
  // the sizes of child widgets if they are not window widgets
2190

2191
  if ( ! hasChildren() )
71✔
2192
    return;
65✔
2193

2194
  for (auto* child : getChildren())
12✔
2195
  {
2196
    auto widget = static_cast<FWidget*>(child);
6✔
2197

2198
    if ( child->isWidget() && ! widget->isWindowWidget() )
6✔
2199
      widget->adjustSize();
6✔
2200
  }
2201
}
2202

2203
//----------------------------------------------------------------------
2204
inline void FWidget::setWindowOffset()
30✔
2205
{
2206
  if ( flags.feature.ignore_padding && ! isDialogWidget() )
30✔
2207
    setTermOffset();
1✔
2208
  else
2209
    woffset = internal::var::root_widget->wclient_offset;
29✔
2210
}
30✔
2211

2212
//----------------------------------------------------------------------
2213
inline void FWidget::setWidgetOffset (const FWidget* parent)
35✔
2214
{
2215
  // Set the widget offset
2216

2217
  if ( ! parent )
35✔
2218
    return;
×
2219

2220
  if ( flags.feature.ignore_padding )
35✔
2221
  {
2222
    woffset.setCoordinates
2223
    (
25✔
2224
      parent->getTermX() - 1,
5✔
2225
      parent->getTermY() - 1,
5✔
2226
      parent->getTermX() + int(parent->getWidth()) - 2,
5✔
2227
      parent->getTermY() + int(parent->getHeight()) - 2
5✔
2228
    );
2229
  }
2230
  else
2231
    woffset = parent->wclient_offset;
30✔
2232
}
2233

2234
//----------------------------------------------------------------------
2235
inline void FWidget::setClientOffset()
71✔
2236
{
2237
  // Set the offset of the widget client area
2238

2239
  wclient_offset.setCoordinates
2240
  (
355✔
2241
    getTermX() - 1 + padding.left,
71✔
2242
    getTermY() - 1 + padding.top,
71✔
2243
    getTermX() - 2 + int(getWidth()) - padding.right,
71✔
2244
    getTermY() - 2 + int(getHeight()) - padding.bottom
71✔
2245
  );
2246
}
71✔
2247

2248
//----------------------------------------------------------------------
2249
inline auto FWidget::isDefaultTheme() -> bool
13✔
2250
{
2251
  FStringList default_themes
2252
  {
2253
    "default8ColorTheme",
2254
    "default16ColorTheme",
2255
    "default8ColorDarkTheme",
2256
    "default16ColorDarkTheme"
2257
  };
78✔
2258

2259
  auto iter = std::find ( default_themes.cbegin()
13✔
2260
                        , default_themes.cend()
2261
                        , getColorTheme()->getClassName() );
26✔
2262
  return iter != default_themes.cend();  // Default theme found
26✔
2263
}
26✔
2264

2265
//----------------------------------------------------------------------
2266
void FWidget::initColorTheme()
20✔
2267
{
2268
  // Sets the default color theme
2269

2270
  if ( getColorTheme().use_count() > 0 && ! isDefaultTheme() )
20✔
2271
    return;  // A user theme is in use
×
2272

2273
  if ( FStartOptions::getInstance().dark_theme )
20✔
2274
  {
2275
    if ( FVTerm::getFOutput()->getMaxColor() < 16 )  // for 8 color mode
×
2276
      setColorTheme<default8ColorDarkTheme>();
×
2277
    else
2278
      setColorTheme<default16ColorDarkTheme>();
×
2279
  }
2280
  else  // Default theme
2281
  {
2282
    if ( FVTerm::getFOutput()->getMaxColor() < 16 )  // for 8 color mode
20✔
2283
      setColorTheme<default8ColorTheme>();
11✔
2284
    else
2285
      setColorTheme<default16ColorTheme>();
9✔
2286
  }
2287
}
2288

2289
//----------------------------------------------------------------------
2290
void FWidget::removeQueuedEvent() const
46✔
2291
{
2292
  auto app_object = FApplication::getApplicationObject();
46✔
2293

2294
  if ( app_object )
46✔
2295
    app_object->removeQueuedEvent(this);
×
2296
}
46✔
2297

2298
//----------------------------------------------------------------------
2299
void FWidget::setStatusbarText (bool enable) const
72✔
2300
{
2301
  if ( ! isEnabled() || ! getStatusBar() )
72✔
2302
    return;
72✔
2303

2304
  if ( enable )
×
2305
  {
2306
    const auto& msg = getStatusbarMessage();
×
2307
    const auto& curMsg = getStatusBar()->getMessage();
×
2308

2309
    if ( curMsg != msg )
×
2310
      getStatusBar()->setMessage(msg);
×
2311
  }
×
2312
  else
2313
  {
2314
    getStatusBar()->clearMessage();
×
2315
  }
2316

2317
  getStatusBar()->drawMessage();
×
2318
}
2319

2320

2321
// non-member functions
2322
//----------------------------------------------------------------------
2323
void detectTerminalSize()
21✔
2324
{
2325
  const auto& r = internal::var::root_widget;
21✔
2326
  FVTerm::getFOutput()->detectTerminalSize();
21✔
2327
  r->adjust_wsize.setRect (1, 1, r->getDesktopWidth(), r->getDesktopHeight());
21✔
2328
  r->woffset.setRect (0, 0, r->getDesktopWidth(), r->getDesktopHeight());
21✔
2329
  r->wclient_offset.setCoordinates
21✔
2330
  (
63✔
2331
    r->padding.left,
21✔
2332
    r->padding.top,
21✔
2333
    int(r->getDesktopWidth()) - 1 - r->padding.right,
21✔
2334
    int(r->getDesktopHeight()) - 1 - r->padding.bottom
21✔
2335
  );
2336
}
21✔
2337

2338
}  // namespace finalcut
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc