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;
36
private int minimum_width;
36
37
/*Animation support */
37
39
protected bool animation_visible = true;
38
40
uint animation_timeout_id = 0;
39
41
protected Gee.Collection<BreadcrumbElement>? old_elements;
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);
96
104
public string get_breadcrumbs_path () {
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
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);
322
333
return total_width;
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;
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);
344
/* Allow extra space for last breadcrumb */
345
w+= 3 * (MINIMUM_BREADCRUMB_WIDTH + padding.left + padding.right);
348
/* Allow enough space after the breadcrumbs for secondary icon and entry */
349
w += 2 * YPAD + MINIMUM_LOCATION_BAR_ENTRY_WIDTH + ICON_WIDTH;
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;
329
355
/* first element (protocol) always untruncated */
330
unowned GLib.List<BreadcrumbElement> l = elements.first ();
331
BreadcrumbElement el = l.data;
333
el.min_width = ICON_WIDTH;
335
available_width -= w;
337
if (number_elements == 0) {
341
l = elements.last ();
344
el.min_width = ICON_WIDTH;
346
available_width -= w;
348
if (available_width < 0) {
351
} else if (number_elements == 0) {
357
el.min_width = ICON_WIDTH;
359
available_width -= w;
361
if (available_width < 0) {
356
elements.first ().data.can_shrink = false;
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;
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;
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);
373
double fraction_reduction = double.max (0.000, 1.0 + (shortfall / free_width));
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;
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);
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) {
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) {
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 ) {
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)) {
429
newelements.add (new BreadcrumbElement (dir));
435
newelements.add (new BreadcrumbElement (dir, this, button_context));
431
437
set_element_icons (protocol, newelements);
432
438
replace_elements (newelements);
575
582
x_render = margin;
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;
592
width_marged -= unfixed * MINIMUM_BREADCRUMB_WIDTH;
583
594
fix_displayed_widths (displayed_breadcrumbs, width_marged);
584
595
distribute_shortfall (displayed_breadcrumbs, width_marged);