~jeremywootten/pantheon-files/fix-backspace-in-columnv-view

« back to all changes in this revision

Viewing changes to libwidgets/Chrome/BasicBreadcrumbsEntry.vala

  • Committer: jeremy at elementaryos
  • Date: 2016-04-30 11:11:40 UTC
  • mfrom: (2023.1.107 pantheon-files)
  • Revision ID: jeremy@elementaryos.org-20160430111140-ez2siepsfxwj9asi
Merge trunk to r2130

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
            TEXT_URI_LIST,
25
25
        }
26
26
        public const double MINIMUM_LOCATION_BAR_ENTRY_WIDTH = 36;
 
27
        public const double MINIMUM_BREADCRUMB_WIDTH = 12;
27
28
        public const double COMPLETION_ALPHA = 0.5;
28
 
        public const int ICON_WIDTH = 24;
 
29
        public const int ICON_WIDTH = 48;
29
30
        protected string placeholder = ""; /*Note: This is not the same as the Gtk.Entry placeholder_text */
30
31
        protected BreadcrumbElement? clicked_element = null;
31
32
        protected string? current_dir_path = null;
32
33
        /* This list will contain all BreadcrumbElement */
33
34
        protected Gee.ArrayList<BreadcrumbElement> elements;
34
35
        private BreadcrumbIconList breadcrumb_icons;
35
 
 
 
36
        private int minimum_width;
36
37
        /*Animation support */
 
38
 
37
39
        protected bool animation_visible = true;
38
40
        uint animation_timeout_id = 0;
39
41
        protected Gee.Collection<BreadcrumbElement>? old_elements;
59
61
            elements = new Gee.ArrayList<BreadcrumbElement> ();
60
62
            old_elements = new Gee.ArrayList<BreadcrumbElement> ();
61
63
            connect_signals ();
 
64
 
 
65
            minimum_width = 100;
62
66
        }
63
67
 
64
68
        protected virtual void configure_style () {
91
95
            PF.FileUtils.split_protocol_from_path (path, out protocol, out newpath);
92
96
            var newelements = new Gee.ArrayList<BreadcrumbElement> ();
93
97
            make_element_list_from_protocol_and_path (protocol, newpath, newelements);
 
98
            GLib.List<BreadcrumbElement> displayed_breadcrumbs = null;
 
99
            get_displayed_breadcrumbs_natural_width (out displayed_breadcrumbs);
 
100
            minimum_width = get_breadcrumbs_minimum_width (displayed_breadcrumbs);
 
101
            this.set_size_request (minimum_width, -1);
94
102
        }
95
103
 
96
104
        public string get_breadcrumbs_path () {
307
315
            queue_draw ();
308
316
        }
309
317
 
310
 
        public double get_displayed_breadcrumbs_width (out GLib.List<BreadcrumbElement> displayed_breadcrumbs) {
 
318
        /** Returns a list of breadcrumbs that are displayed in natural order - that is, the breadcrumb at the start
 
319
          * of the pathbar is at the start of the list
 
320
         **/  
 
321
        public double get_displayed_breadcrumbs_natural_width (out GLib.List<BreadcrumbElement> displayed_breadcrumbs) {
311
322
            double total_width = 0.0;
312
323
            displayed_breadcrumbs = null;
313
324
            foreach (BreadcrumbElement element in elements) {
314
325
                if (element.display) {
315
 
                    total_width += element.width;
316
 
                    element.max_width = -1;
317
 
                    element.min_width = -1;
 
326
                    total_width += element.natural_width;
 
327
                    element.can_shrink = true;
 
328
                    element.display_width = -1;
318
329
                    displayed_breadcrumbs.prepend (element);
319
330
                }
320
331
            }
322
333
            return total_width;
323
334
        }
324
335
 
 
336
        private int get_breadcrumbs_minimum_width (GLib.List<BreadcrumbElement> displayed_breadcrumbs) {
 
337
            var l = (int)displayed_breadcrumbs.length ();
 
338
            var w = displayed_breadcrumbs.first ().data.natural_width;
 
339
            if (l > 1) {
 
340
                var state = button_context.get_state ();
 
341
                var padding = button_context.get_padding (state);
 
342
                w += (l -1) * (MINIMUM_BREADCRUMB_WIDTH + padding.left + padding.right);
 
343
 
 
344
                /* Allow extra space for last breadcrumb */
 
345
                w+= 3 * (MINIMUM_BREADCRUMB_WIDTH + padding.left + padding.right);
 
346
            }
 
347
 
 
348
            /* Allow enough space after the breadcrumbs for secondary icon and entry */
 
349
            w += 2 * YPAD + MINIMUM_LOCATION_BAR_ENTRY_WIDTH + ICON_WIDTH; 
 
350
 
 
351
            return (int) (w);
 
352
        }
 
353
 
325
354
        private void fix_displayed_widths (GLib.List<BreadcrumbElement> elements, double target_width) {
326
 
            uint number_elements = elements.length ();
327
 
            double available_width = target_width;
328
 
            double w;
329
355
            /* first element (protocol) always untruncated */
330
 
            unowned GLib.List<BreadcrumbElement> l = elements.first ();
331
 
            BreadcrumbElement el = l.data;
332
 
            w = el.width;
333
 
            el.min_width = ICON_WIDTH;
334
 
            el.max_width = -1;
335
 
            available_width -= w;
336
 
            number_elements--;
337
 
            if (number_elements == 0) {
338
 
                return;
339
 
            }
340
 
 
341
 
            l = elements.last ();
342
 
            el = l.data;
343
 
            w = el.width;
344
 
            el.min_width = ICON_WIDTH;
345
 
            el.max_width = -1;
346
 
            available_width -= w;
347
 
            number_elements--;
348
 
            if (available_width < 0) {
349
 
                el.min_width = -1;
350
 
                return;
351
 
            } else if (number_elements == 0) {
352
 
                return;
353
 
            }
354
 
 
355
 
            el = l.prev.data;
356
 
            w = el.width;
357
 
            el.min_width = ICON_WIDTH;
358
 
            el.max_width = -1;
359
 
            available_width -= w;
360
 
            number_elements--;
361
 
            if (available_width < 0) {
362
 
                el.min_width = -1;
363
 
                return;
364
 
            }
 
356
            elements.first ().data.can_shrink = false;
365
357
            return;
366
358
        }
367
359
 
368
360
        private void distribute_shortfall (GLib.List<BreadcrumbElement> elements, double target_width) {
369
 
            double shortfall = double.max (ICON_WIDTH, target_width);
 
361
            double shortfall = target_width;
370
362
            double free_width = 0;
371
 
            foreach (BreadcrumbElement el in elements) {
372
 
                shortfall -= el.width;
373
 
                if (el.min_width < 0) {
374
 
                    free_width += el.width;
375
 
                }
376
 
            }
377
 
            double fraction_reduction = double.max (0.01, 1 + (shortfall / free_width));
378
 
            foreach (BreadcrumbElement el in elements) {
379
 
                if (el.min_width == -1) {
380
 
                    el.max_width = el.width * fraction_reduction;
381
 
                }
 
363
            uint index = 0;
 
364
            uint length = elements.length ();
 
365
            /* Calculate the amount by which the breadcrumbs can be shrunk excluding the fixed and last */
 
366
            foreach (BreadcrumbElement el in elements) {
 
367
                shortfall -= el.natural_width;
 
368
                if (++index < length && el.can_shrink) {
 
369
                    free_width += (el.natural_width - MINIMUM_BREADCRUMB_WIDTH);
 
370
                }
 
371
            }
 
372
 
 
373
            double fraction_reduction = double.max (0.000, 1.0 + (shortfall / free_width));
 
374
            index = 0;
 
375
            foreach (BreadcrumbElement el in elements) {
 
376
                if (++index < length && el.can_shrink) {
 
377
                    el.display_width = (el.natural_width - MINIMUM_BREADCRUMB_WIDTH) * fraction_reduction + MINIMUM_BREADCRUMB_WIDTH;
 
378
                }
 
379
            }
 
380
 
 
381
            var remaining_shortfall = -(shortfall + free_width);
 
382
            if (remaining_shortfall > 0) {
 
383
                var el = elements.last ().data;
 
384
                el.can_shrink = true;
 
385
                /* The last breadcrumb does not shrink as much as the others */
 
386
                el.display_width = double.max (4 * MINIMUM_BREADCRUMB_WIDTH, el.natural_width - remaining_shortfall);
382
387
            }
383
388
        }
384
389
 
385
390
        protected BreadcrumbElement? get_element_from_coordinates (int x, int y) {
386
391
            double width = get_allocated_width () - ICON_WIDTH;
 
392
            double height = get_allocated_height ();
387
393
            double x_render = is_RTL ? width : 0;
388
394
            foreach (BreadcrumbElement element in elements) {
389
395
                if (element.display) {
390
396
                    if (is_RTL) {
391
 
                        x_render -= element.real_width;
 
397
                        x_render -= (element.real_width + height / 2); /* add width of arrow to element width */
392
398
                        if (x >= x_render - 5) {
393
399
                            return element;
394
400
                        }
395
401
                    } else {
396
 
                        x_render += element.real_width;
 
402
                        x_render += (element.real_width + height / 2); /* add width of arrow to element width */
397
403
                        if (x <= x_render - 5 ) {
398
404
                            return element;
399
405
                        }
423
429
                                                               Gee.ArrayList<BreadcrumbElement> newelements) {
424
430
            /* Ensure the breadcrumb texts are escaped strings whether or not the parameter newpath was supplied escaped */
425
431
            string newpath = PF.FileUtils.escape_uri (Uri.unescape_string (path) ?? path);
426
 
            newelements.add (new BreadcrumbElement (protocol));
 
432
            newelements.add (new BreadcrumbElement (protocol, this, button_context));
427
433
            foreach (string dir in newpath.split (Path.DIR_SEPARATOR_S)) {
428
434
                if (dir != "")
429
 
                    newelements.add (new BreadcrumbElement (dir));
 
435
                    newelements.add (new BreadcrumbElement (dir, this, button_context));
430
436
            }
431
437
            set_element_icons (protocol, newelements);
432
438
            replace_elements (newelements);
441
447
                if (icon.protocol && protocol.has_prefix (icon.path)) {
442
448
                    newelements[0].set_icon (icon.icon);
443
449
                    newelements[0].set_icon_name (icon.icon_name);
444
 
                    newelements[0].text_displayed = icon.text_displayed;
 
450
                    newelements[0].text_for_display = icon.text_displayed;
 
451
                    newelements[0].text_is_displayed = (icon.text_displayed != null);
445
452
                    break;
446
453
                } else if (!icon.protocol && icon.exploded.length <= newelements.size) {
447
454
                    bool found = true;
462
469
                        newelements[h].display = true;
463
470
                        newelements[h].set_icon (icon.icon);
464
471
                        newelements[h].set_icon_name (icon.icon_name);
465
 
                        newelements[h].display_text = (icon.text_displayed != null) || !icon.break_loop;
466
 
                        newelements[h].text_displayed = icon.text_displayed;
 
472
                        newelements[h].text_is_displayed = (icon.text_displayed != null) || !icon.break_loop;
 
473
                        newelements[h].text_for_display = icon.text_displayed;
467
474
 
468
475
                        if (icon.break_loop)
469
476
                            break;
566
573
                double margin = YPAD;
567
574
 
568
575
                /* Ensure there is an editable area to the right of the breadcrumbs */
569
 
                double width_marged = width - 2*margin - MINIMUM_LOCATION_BAR_ENTRY_WIDTH;
570
 
                double height_marged = height - 2*margin;
 
576
                double width_marged = width - 2 * margin - MINIMUM_LOCATION_BAR_ENTRY_WIDTH - ICON_WIDTH;
 
577
                double height_marged = height - 2 * margin;
571
578
                double x_render;
572
579
                if (is_RTL) {
573
580
                    x_render = width - margin;
575
582
                    x_render = margin;
576
583
                }
577
584
                GLib.List<BreadcrumbElement> displayed_breadcrumbs = null;
578
 
                double max_width = get_displayed_breadcrumbs_width (out displayed_breadcrumbs);
 
585
                double max_width = get_displayed_breadcrumbs_natural_width (out displayed_breadcrumbs);
 
586
                /* each element must not be bigger than the width/breadcrumbs count */
 
587
                double total_arrow_width = displayed_breadcrumbs.length () * (height_marged / 2 + padding.left);
 
588
                width_marged -= total_arrow_width;
579
589
                if (max_width > width_marged) { /* let's check if the breadcrumbs are bigger than the widget */
580
 
                    /* each element must not be bigger than the width/breadcrumbs count */
581
 
                    double total_arrow_width = displayed_breadcrumbs.length () * (height_marged / 2 + padding.left);
582
 
                    width_marged -= total_arrow_width;
 
590
                    var unfixed = displayed_breadcrumbs.length () - 2; 
 
591
                    if (unfixed > 0) {
 
592
                        width_marged -= unfixed * MINIMUM_BREADCRUMB_WIDTH;
 
593
                    }
583
594
                    fix_displayed_widths (displayed_breadcrumbs, width_marged);
584
595
                    distribute_shortfall (displayed_breadcrumbs, width_marged);
585
596
                }
643
654
            return true;
644
655
        }
645
656
 
 
657
        public int get_minimum_width () {
 
658
            return minimum_width;
 
659
        }
 
660
 
646
661
        /**Functions to aid testing **/
647
662
        public string get_first_element_icon_name () {
648
663
            if (elements.size >= 1) {