Expander.vala
/*
Copyright (C) 2012 2014 2015 Johan Mattsson
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 3 of the
License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
*/
using Cairo;
using Math;
namespace BirdFont {
public class Expander : GLib.Object {
private const double HEADLINE_MARGIN = 4;
public double x = 7;
public double y = 5;
public double scroll = 0;
public double w = 6;
public double h = 5;
public double margin = 0;
protected double opacity = 0;
protected bool active = false;
public Gee.ArrayList<Tool> tool;
bool persist = false;
bool unique = false;
double content_height = 0;
string? headline;
Text title;
public bool visible = true;
Surface? cached = null;
public Expander (string? headline = null) {
this.headline = headline;
title = new Text ();
if (headline != null) {
title.set_text ((!) headline);
}
tool = new Gee.ArrayList<Tool> ();
}
public void clear_cache () {
cached = null;
}
public void set_headline (Text h) {
headline = h.get_text ();
title = h;
}
public double get_content_height () {
return content_height;
}
/** Returns true if tools can be used with the current canvas after
* they have been selectes and false if they are a commands to be executed.
*/
public bool is_persistent () {
return persist;
}
/** Returns true if all other tools in thid expander should be deselected
* when a tool is selected.
*/
public bool is_unique () {
return unique;
}
public void set_persistent (bool p) {
persist = p;
}
public void set_unique (bool u) {
unique = u;
}
public void update_tool_position () {
double scale = Toolbox.get_scale ();
double margin_small = 5 * scale;
double xt = x;
double yt = y + margin_small; // + scroll
bool new_row = false;
bool has_visible_tools = false;
Tool previous;
bool first_row;
foreach (Tool t in tool) {
if (t.tool_is_visible ()) {
has_visible_tools = true;
break;
}
}
if (!has_visible_tools) {
content_height = 0;
return;
}
foreach (Tool t in tool) {
if (t is ZoomBar) {
t.w = Toolbox.allocation_width * scale;
t.h = 10 * scale; // 7
} else if (t is LabelTool) {
t.w = Toolbox.allocation_width * scale;
t.h = 22 * scale;
} else if (t is FontName) {
t.w = Toolbox.allocation_width * scale;
t.h = 20 * scale;
} else if (t is KerningRange) {
t.w = Toolbox.allocation_width * scale;
t.h = 17 * scale;
} else if (t is LayerLabel) {
t.w = Toolbox.allocation_width * scale;
t.h = 21 * scale;
} else if (t is ColorPicker) {
t.w = Toolbox.allocation_width * scale;
t.h = 5 * ((ColorPicker) t).bar_height;
} else {
t.w = 33 * scale;
t.h = (33 / 1.11) * scale;
}
}
if (tool.size > 0) {
content_height = tool.get (0).h + margin_small;
} else {
content_height = 0;
}
if (headline != null && tool.size > 0) {
yt += 17 * scale + HEADLINE_MARGIN;
content_height += 17 * scale + HEADLINE_MARGIN;
}
if (tool.size > 0) {
previous = tool.get (0);
first_row = true;
foreach (Tool t in tool) {
if (t.tool_is_visible ()) {
new_row = xt + t.w > Toolbox.allocation_width - 7 * scale;
if (t is ZoomBar) {
t.x = xt;
t.y = yt;
yt += t.h + 7 * scale;
previous = t;
continue;
}
if (previous is ZoomBar) {
content_height += t.h;
}
if (new_row && !first_row) {
content_height += previous.h;
xt = x;
yt += previous.h;
if (!(t is LabelTool) && !(previous is LayerLabel)) {
yt += 7 * scale;
}
if (!(previous is LayerLabel)) {
content_height += margin_small;
}
}
t.x = xt;
t.y = yt;
xt += t.w + 7 * scale;
if (previous is ZoomBar) {
content_height += 7 * scale;
} else if (previous is KerningRange) {
content_height += 10 * scale;
}
previous = t;
first_row = false;
}
}
content_height += 5 * scale;
}
if (unlikely (content_height < 0)) {
warning (@"content_height < 0");
}
}
public void set_scroll (double scroll) {
this.scroll = scroll;
}
public void set_offset (double ty) {
y = ty;
update_tool_position ();
}
public void redraw () {
Toolbox.redraw_tool_box ();
}
public void add_tool (Tool t, int position = -1) {
if (position < 0) {
tool.add (t);
} else {
return_if_fail (position <= tool.size);
tool.insert (position, t);
}
t.redraw_tool.connect (() => {
cached = null;
});
update_tool_position ();
t.select_action.connect ((selected) => {
MainWindow.get_toolbox ().redraw ((int) x, (int) y, (int) w + 300, (int) (h + margin));
if (is_unique ()) {
foreach (var deselected in tool) {
if (selected.get_id () != deselected.get_id ()) {
deselected.set_selected (false);
}
}
}
if (!selected.new_selection && selected.persistent) {
if (is_persistent ()) {
selected.set_selected (true);
} else {
selected.set_selected (false);
}
}
selected.new_selection = false;
});
}
public bool is_over (double xp, double yp) {
double yt = y + scroll + 2;
return yt - 7 <= yp <= yt + 7 && xp < 17;
}
public bool set_active (bool a) {
bool r = (active != a);
opacity = (a) ? 1 : 0;
active = a;
return r;
}
public void cache () {
if (cached == null) {
Surface workbench = Screen.create_background_surface (1, 1);
Context context = new Context (workbench);
draw (context);
}
}
public void draw (Context cr) {
Surface cache;
if (unlikely (cached == null)) {
Context cc;
double text_height = 17 * Toolbox.get_scale ();
double offset_y = 0;
cache = Screen.create_background_surface (Toolbox.allocation_width, (int) (h + content_height));
cc = new Context (cache);
cc.scale(Screen.get_scale(), Screen.get_scale());
if (tool.size > 0 && headline != null) {
Theme.text_color (title, "Text Tool Box");
title.set_font_size (text_height);
title.draw_at_top (cc, x, 0);
offset_y = text_height + HEADLINE_MARGIN;
}
draw_content (cc, offset_y);
cached = (!) cache;
}
if (cached != null) {
cache = (!) cached;
cr.set_antialias (Cairo.Antialias.NONE);
Screen.paint_background_surface (cr, cache, 0, (int) (y + scroll));
}
}
public void draw_content (Context cr, double text_end) {
double offset_y = 0;
double offset_x = 0;
update_tool_position ();
if (tool.size > 0) {
offset_x = tool.get (0).x;
offset_y = tool.get (0).y - text_end;
}
cr.save ();
foreach (Tool t in tool) {
if (t.tool_is_visible ()) {
t.draw_tool (cr, offset_x - x, offset_y);
}
}
cr.restore ();
}
}
}