summaryrefslogtreecommitdiff
path: root/src/renderers
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2015-04-18 15:42:59 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2015-04-18 15:42:59 +0200
commit84a27086bbd9f493128b354300f9c77ccb32a56b (patch)
tree977cb323f0ac6953f10bc20d84f45ebd5a6d4535 /src/renderers
parentb683ce2789d95b2e9f221e75adc30efd91cfb901 (diff)
Imported Upstream version 0.6.0upstream/0.6.0
Diffstat (limited to 'src/renderers')
-rw-r--r--src/renderers/centerRenderer.vala214
-rw-r--r--src/renderers/pieRenderer.vala768
-rwxr-xr-x[-rw-r--r--]src/renderers/pieWindow.vala216
-rw-r--r--src/renderers/sliceRenderer.vala68
4 files changed, 990 insertions, 276 deletions
diff --git a/src/renderers/centerRenderer.vala b/src/renderers/centerRenderer.vala
index fab633e..e94714f 100644
--- a/src/renderers/centerRenderer.vala
+++ b/src/renderers/centerRenderer.vala
@@ -1,25 +1,25 @@
-/*
-Copyright (c) 2011 by Simon Schneegans
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option)
-any later version.
-
-This program 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 General Public License for
-more details.
-
-You should have received a copy of the GNU General Public License along with
-this program. If not, see <http://www.gnu.org/licenses/>.
-*/
+/////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2011-2015 by Simon Schneegans
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or (at
+// your option) any later version.
+//
+// This program 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
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+/////////////////////////////////////////////////////////////////////////
using GLib.Math;
namespace GnomePie {
-/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
/// Renders the center of a Pie.
/////////////////////////////////////////////////////////////////////////
@@ -30,26 +30,26 @@ public class CenterRenderer : GLib.Object {
/////////////////////////////////////////////////////////////////////
private unowned PieRenderer parent;
-
+
/////////////////////////////////////////////////////////////////////
/// The caption drawn in the center. Changes when the active slice
/// changes.
/////////////////////////////////////////////////////////////////////
-
+
private unowned Image? caption;
-
+
/////////////////////////////////////////////////////////////////////
/// The color of the currently active slice. Used to colorize layers.
/////////////////////////////////////////////////////////////////////
-
+
private Color color;
-
+
/////////////////////////////////////////////////////////////////////
/// Two AnimatedValues: alpha is for global transparency (when
/// fading in/out), activity is 1.0 if there is an active slice and
/// 0.0 if there is no active slice.
/////////////////////////////////////////////////////////////////////
-
+
private AnimatedValue activity;
private AnimatedValue alpha;
@@ -64,22 +64,22 @@ public class CenterRenderer : GLib.Object {
this.color = new Color();
this.caption = null;
}
-
+
/////////////////////////////////////////////////////////////////////
/// Initiates the fade-out animation by resetting the targets of the
/// AnimatedValues to 0.0.
/////////////////////////////////////////////////////////////////////
-
+
public void fade_out() {
this.activity.reset_target(0.0, Config.global.theme.fade_out_time);
this.alpha.reset_target(0.0, Config.global.theme.fade_out_time);
}
-
+
/////////////////////////////////////////////////////////////////////
/// Should be called if the active slice of the PieRenderer changes.
/// The members activity, caption and color are set accordingly.
/////////////////////////////////////////////////////////////////////
-
+
public void set_active_slice(SliceRenderer? active_slice) {
if (active_slice == null) {
this.activity.reset_target(0.0, Config.global.theme.transition_time);
@@ -89,104 +89,136 @@ public class CenterRenderer : GLib.Object {
this.color = active_slice.color;
}
}
-
+
/////////////////////////////////////////////////////////////////////
/// Draws all center layers and the caption.
/////////////////////////////////////////////////////////////////////
-
- public void draw(double frame_time, Cairo.Context ctx, double angle, double distance) {
+
+ public void draw(double frame_time, Cairo.Context ctx, double angle, int slice_track) {
// get all center_layers
- var layers = Config.global.theme.center_layers;
-
+ var layers = Config.global.theme.center_layers;
+
// update the AnimatedValues
this.activity.update(frame_time);
this.alpha.update(frame_time);
-
- // draw each layer
- foreach (var layer in layers) {
- ctx.save();
+
+ // draw each layer
+ foreach (var layer in layers) {
+ ctx.save();
// calculate all values needed for animation/drawing
- double active_speed = (layer.active_rotation_mode == CenterLayer.RotationMode.TO_MOUSE) ?
+ double active_speed = (layer.active_rotation_mode == CenterLayer.RotationMode.TO_MOUSE) ?
0.0 : layer.active_rotation_speed;
- double inactive_speed = (layer.inactive_rotation_mode == CenterLayer.RotationMode.TO_MOUSE) ?
+ double inactive_speed = (layer.inactive_rotation_mode == CenterLayer.RotationMode.TO_MOUSE) ?
0.0 : layer.inactive_rotation_speed;
- double max_scale = layer.active_scale*this.activity.val
- + layer.inactive_scale*(1.0-this.activity.val);
- double max_alpha = layer.active_alpha*this.activity.val
+ double max_scale = layer.active_scale*this.activity.val
+ + layer.inactive_scale*(1.0-this.activity.val);
+ double max_alpha = layer.active_alpha*this.activity.val
+ layer.inactive_alpha*(1.0-this.activity.val);
- double colorize = ((layer.active_colorize == true) ? this.activity.val : 0.0)
+ double colorize = ((layer.active_colorize == true) ? this.activity.val : 0.0)
+ ((layer.inactive_colorize == true) ? 1.0 - this.activity.val : 0.0);
- double max_rotation_speed = active_speed*this.activity.val
+ double max_rotation_speed = active_speed*this.activity.val
+ inactive_speed*(1.0-this.activity.val);
- CenterLayer.RotationMode rotation_mode = ((this.activity.val > 0.5) ?
+ CenterLayer.RotationMode rotation_mode = ((this.activity.val > 0.5) ?
layer.active_rotation_mode : layer.inactive_rotation_mode);
-
- if (rotation_mode == CenterLayer.RotationMode.TO_MOUSE) {
- double diff = angle-layer.rotation;
- max_rotation_speed = layer.active_rotation_speed*this.activity.val
- + layer.inactive_rotation_speed*(1.0-this.activity.val);
- double smoothy = fabs(diff) < 0.9 ? fabs(diff) + 0.1 : 1.0;
- double step = max_rotation_speed*frame_time*smoothy;
-
+
+ if (rotation_mode == CenterLayer.RotationMode.TO_MOUSE) {
+ double diff = angle-layer.rotation;
+ max_rotation_speed = layer.active_rotation_speed*this.activity.val
+ + layer.inactive_rotation_speed*(1.0-this.activity.val);
+ double smoothy = fabs(diff) < 0.9 ? fabs(diff) + 0.1 : 1.0;
+ double step = max_rotation_speed*frame_time*smoothy;
+
if (fabs(diff) <= step || fabs(diff) >= 2.0*PI - step)
- layer.rotation = angle;
- else {
- if ((diff > 0 && diff < PI) || diff < -PI) layer.rotation += step;
- else layer.rotation -= step;
+ layer.rotation = angle;
+ else {
+ if ((diff > 0 && diff < PI) || diff < -PI) layer.rotation += step;
+ else layer.rotation -= step;
}
-
- } else if (rotation_mode == CenterLayer.RotationMode.TO_ACTIVE) {
- max_rotation_speed *= this.activity.val;
-
- double slice_angle = parent.slice_count() > 0 ? 2*PI/parent.slice_count() : 0;
- double direction = (int)((angle+0.5*slice_angle) / (slice_angle))*slice_angle;
- double diff = direction-layer.rotation;
- double step = max_rotation_speed*frame_time;
-
+
+ } else if (rotation_mode == CenterLayer.RotationMode.TO_ACTIVE) {
+ max_rotation_speed *= this.activity.val;
+
+ double slice_angle = parent.total_slice_count > 0 ? 2*PI/parent.total_slice_count : 0;
+ double direction = (int)((angle+0.5*slice_angle) / (slice_angle))*slice_angle;
+ double diff = direction-layer.rotation;
+ double step = max_rotation_speed*frame_time;
+
if (fabs(diff) <= step || fabs(diff) >= 2.0*PI - step)
- layer.rotation = direction;
- else {
- if ((diff > 0 && diff < PI) || diff < -PI) layer.rotation += step;
- else layer.rotation -= step;
+ layer.rotation = direction;
+ else {
+ if ((diff > 0 && diff < PI) || diff < -PI) layer.rotation += step;
+ else layer.rotation -= step;
}
-
- } else layer.rotation += max_rotation_speed*frame_time;
-
- layer.rotation = fmod(layer.rotation+2*PI, 2*PI);
-
- if (colorize > 0.0) ctx.push_group();
-
- // transform the context
- ctx.rotate(layer.rotation);
- ctx.scale(max_scale, max_scale);
-
- // paint the layer
- layer.image.paint_on(ctx, this.alpha.val*max_alpha);
-
+
+ } else layer.rotation += max_rotation_speed*frame_time;
+
+ layer.rotation = fmod(layer.rotation+2*PI, 2*PI);
+
+ if (colorize > 0.0) ctx.push_group();
+
+ // transform the context
+ ctx.rotate(layer.rotation);
+ ctx.scale(max_scale, max_scale);
+
+ // paint the layer
+ layer.image.paint_on(ctx, this.alpha.val*max_alpha);
+
// colorize it, if necessary
if (colorize > 0.0) {
ctx.set_operator(Cairo.Operator.ATOP);
ctx.set_source_rgb(this.color.r, this.color.g, this.color.b);
ctx.paint_with_alpha(colorize);
-
+
ctx.set_operator(Cairo.Operator.OVER);
ctx.pop_group_to_source();
- ctx.paint();
- }
-
+ ctx.paint();
+ }
+
ctx.restore();
}
-
+
// draw caption
if (Config.global.theme.caption && caption != null && this.activity.val > 0) {
- ctx.save();
+ ctx.save();
ctx.identity_matrix();
- int pos = this.parent.size/2;
- ctx.translate(pos, (int)(Config.global.theme.caption_position) + pos);
+ ctx.translate(this.parent.center_x, (int)(Config.global.theme.caption_position) + this.parent.center_y);
caption.paint_on(ctx, this.activity.val*this.alpha.val);
ctx.restore();
}
+
+ //scroll pie
+ if (this.alpha.val > 0.1
+ && this.parent.original_visible_slice_count < this.parent.slice_count()
+ && this.parent.original_visible_slice_count > 0) {
+ int np= (this.parent.slice_count()+this.parent.original_visible_slice_count -1)/this.parent.original_visible_slice_count;
+ int cp= this.parent.first_slice_idx / this.parent.original_visible_slice_count;
+ int r= 8; //circle radious
+ int dy= 20; //distance between circles
+ double a= 0.8 * this.alpha.val;
+ int dx= (int)Config.global.theme.center_radius + r + 10;
+ if (this.parent.center_x + dx > this.parent.size_w)
+ dx= -dx; //no right side, put scroll in the left size
+ ctx.save();
+ ctx.identity_matrix();
+ ctx.translate(this.parent.center_x + dx, this.parent.center_y - (np-1)*dy/2);
+ for (int i=0; i<np; i++) {
+ ctx.arc( 0, 0, r, 0, 2*PI );
+ if (i == cp){
+ ctx.set_source_rgba(0.3,0.3,0.3, a); //light gray stroke
+ ctx.stroke_preserve();
+ ctx.set_source_rgba(1,1,1, a); //white fill
+ ctx.fill(); //current
+ } else {
+ ctx.set_source_rgba(1,1,1, a); //white stroke
+ ctx.stroke_preserve();
+ ctx.set_source_rgba(0.3,0.3,0.3, a/4); //light gray fill
+ ctx.fill(); //current
+ }
+ ctx.translate(0, dy);
+ }
+ ctx.restore();
+ }
}
}
diff --git a/src/renderers/pieRenderer.vala b/src/renderers/pieRenderer.vala
index 8085758..2edee09 100644
--- a/src/renderers/pieRenderer.vala
+++ b/src/renderers/pieRenderer.vala
@@ -1,19 +1,19 @@
-/*
-Copyright (c) 2011 by Simon Schneegans
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option)
-any later version.
-
-This program 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 General Public License for
-more details.
-
-You should have received a copy of the GNU General Public License along with
-this program. If not, see <http://www.gnu.org/licenses/>.
-*/
+/////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2011-2015 by Simon Schneegans
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or (at
+// your option) any later version.
+//
+// This program 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
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+/////////////////////////////////////////////////////////////////////////
using GLib.Math;
@@ -49,13 +49,89 @@ public class PieRenderer : GLib.Object {
/// The width and height of the Pie in pixels.
/////////////////////////////////////////////////////////////////////
- public int size { get; private set; }
+ public int size_w { get; private set; }
+ public int size_h { get; private set; }
+
+ /////////////////////////////////////////////////////////////////////
+ /// Center position relative to window top-left corner
+ /////////////////////////////////////////////////////////////////////
+
+ public int center_x { get; private set; }
+ public int center_y { get; private set; }
+
+ ////////////////////////////////////////////////////////////////////
+ /// Possible show pie modes.
+ /// FULL_PIE: Show the pie as a complete circle.
+ /// HPIE_LEFT: Eat half pie so it can be shown at the left of the screen.
+ /// HPIE_RIGHT: Eat half pie so it can be shown at the right of the screen.
+ /// HPIE_TOP: Eat half pie so it can be shown at the top of the screen.
+ /// HPIE_BOTTOM: Eat half pie so it can be shown at the bottom of the screen.
+ /// CPIE_TOP_LEFT: Eat 3/4 pie so it can be shown at the top-left corner.
+ /// CPIE_TOP_RIGHT: Eat 3/4 pie so it can be shown at the top-right corner.
+ /// CPIE_BOT_LEFT: Eat 3/4 pie so it can be shown at the bottom-left corner.
+ /// CPIE_BOT_RIGHT: Eat 3/4 pie so it can be shown at the bottom-right corner.
/////////////////////////////////////////////////////////////////////
- /// True if the pie should close when it's trigger is released.
+
+ public enum ShowPieMode {
+ FULL_PIE,
+ HPIE_LEFT, HPIE_RIGHT, HPIE_TOP, HPIE_BOTTOM,
+ CPIE_TOP_LEFT, CPIE_TOP_RIGHT, CPIE_BOT_LEFT, CPIE_BOT_RIGHT}
+
/////////////////////////////////////////////////////////////////////
+ /// Show pie mode: full, half-circle, corner
+ /////////////////////////////////////////////////////////////////////
+
+ public ShowPieMode pie_show_mode { get; private set; default= ShowPieMode.FULL_PIE; }
+
+ /////////////////////////////////////////////////////////////////////
+ /// Number of visible slices
+ /////////////////////////////////////////////////////////////////////
+
+ public int visible_slice_count { get; private set; }
- public bool turbo_mode { get; private set; default=false; }
+ public int original_visible_slice_count { get; private set; }
+
+ /////////////////////////////////////////////////////////////////////
+ /// Number of slices in full pie (visible or not)
+ /////////////////////////////////////////////////////////////////////
+
+ public int total_slice_count { get; private set; }
+
+ /////////////////////////////////////////////////////////////////////
+ /// Maximun number of visible slices in a full pie
+ /////////////////////////////////////////////////////////////////////
+
+ public int max_visible_slices { get; private set; }
+
+ /////////////////////////////////////////////////////////////////////
+ /// The index of the first visible slice
+ /////////////////////////////////////////////////////////////////////
+
+ public int first_slice_idx { get; private set; }
+
+ /////////////////////////////////////////////////////////////////////
+ /// Angular position of the first visible slice
+ /////////////////////////////////////////////////////////////////////
+
+ public double first_slice_angle { get; private set; }
+
+ /////////////////////////////////////////////////////////////////////
+ /// Index of the slice where to go when up/down/left/right key is pressed
+ /// or -1 if that side of the pie was eaten
+ /////////////////////////////////////////////////////////////////////
+
+ public int up_slice_idx { get; private set; }
+ public int down_slice_idx { get; private set; }
+ public int left_slice_idx { get; private set; }
+ public int right_slice_idx { get; private set; }
+
+
+ /////////////////////////////////////////////////////////////////////
+ /// The ID of the currently loaded Pie.
+ /////////////////////////////////////////////////////////////////////
+
+ public string id { get; private set; }
/////////////////////////////////////////////////////////////////////
/// True if the pie is currently navigated with the keyboard. This is
@@ -77,6 +153,11 @@ public class PieRenderer : GLib.Object {
private CenterRenderer center;
/////////////////////////////////////////////////////////////////////
+ /// Maximum distance from the center that activates the slices
+ /////////////////////////////////////////////////////////////////////
+ private int activation_range;
+
+ /////////////////////////////////////////////////////////////////////
/// C'tor, initializes members.
/////////////////////////////////////////////////////////////////////
@@ -85,7 +166,35 @@ public class PieRenderer : GLib.Object {
this.center = new CenterRenderer(this);
this.quickaction = -1;
this.active_slice = -2;
- this.size = 0;
+ this.size_w = 0;
+ this.size_h = 0;
+ this.activation_range= 300;
+
+ this.max_visible_slices= Config.global.max_visible_slices;
+
+ set_show_mode(ShowPieMode.FULL_PIE);
+ }
+
+
+ private void get_mouse_and_screen(out int mousex, out int mousey, out int screenx, out int screeny) {
+ // get the mouse position and screen resolution
+ double x = 0.0;
+ double y = 0.0;
+
+ var display = Gdk.Display.get_default();
+ var manager = display.get_device_manager();
+ GLib.List<weak Gdk.Device?> list = manager.list_devices(Gdk.DeviceType.MASTER);
+
+ foreach(var device in list) {
+ if (device.input_source != Gdk.InputSource.KEYBOARD) {
+ Gdk.Screen screen;
+ device.get_position( out screen, out x, out y );
+ }
+ }
+ mousex= (int) x;
+ mousey= (int) y;
+ screenx= Gdk.Screen.width();
+ screeny= Gdk.Screen.height();
}
/////////////////////////////////////////////////////////////////////
@@ -95,6 +204,8 @@ public class PieRenderer : GLib.Object {
public void load_pie(Pie pie) {
this.slices.clear();
+ this.id = pie.id;
+
int count = 0;
foreach (var group in pie.action_groups) {
foreach (var action in group.actions) {
@@ -110,18 +221,200 @@ public class PieRenderer : GLib.Object {
}
}
- this.turbo_mode = PieManager.get_is_turbo(pie.id);
-
this.set_highlighted_slice(this.quickaction);
- this.size = (int)fmax(2*Config.global.theme.radius + 2*Config.global.theme.slice_radius*Config.global.theme.max_zoom,
- 2*Config.global.theme.center_radius);
+ ShowPieMode showpie= ShowPieMode.FULL_PIE;
+ //set full pie to determine the number of visible slices
+ set_show_mode(showpie);
+
+ int sz0= (int)fmax(2*Config.global.theme.radius + 2*Config.global.theme.visible_slice_radius*Config.global.theme.max_zoom,
+ 2*Config.global.theme.center_radius);
+
+ int sz= sz0;
// increase size if there are many slices
- if (slices.size > 0) {
- this.size = (int)fmax(this.size,
- (((Config.global.theme.slice_radius + Config.global.theme.slice_gap)/tan(PI/slices.size))
- + Config.global.theme.slice_radius)*2*Config.global.theme.max_zoom);
+ if (this.total_slice_count > 0) {
+ sz = (int)fmax(sz0,
+ (((Config.global.theme.slice_radius + Config.global.theme.slice_gap)/tan(PI/this.total_slice_count))
+ + Config.global.theme.visible_slice_radius)*2*Config.global.theme.max_zoom);
+ }
+
+
+
+
+ // get mouse position and screen resolution
+ int mouse_x, mouse_y, screen_x, screen_y;
+ get_mouse_and_screen( out mouse_x, out mouse_y, out screen_x, out screen_y );
+
+ //reduce the window size if needed to get closer to the actual mouse position
+ int reduce_szx= 1;
+ int reduce_szy= 1;
+
+ if (PieManager.get_is_auto_shape(pie.id) && !PieManager.get_is_centered(pie.id)) {
+ //set the best show mode that put the mouse near the center
+ if (mouse_x < sz/2) {
+ if (mouse_y < sz/2)
+ showpie= ShowPieMode.CPIE_TOP_LEFT; //show 1/4 pie
+ else if (screen_y > 0 && screen_y-mouse_y < sz/2)
+ showpie= ShowPieMode.CPIE_BOT_LEFT; //show 1/4 pie
+ else
+ showpie= ShowPieMode.HPIE_LEFT; //show 1/2 pie
+
+ } else if (mouse_y < sz/2) {
+ if (screen_x > 0 && screen_x-mouse_x < sz/2)
+ showpie= ShowPieMode.CPIE_TOP_RIGHT; //show 1/4 pie
+ else
+ showpie= ShowPieMode.HPIE_TOP; //show 1/2 pie
+
+ } else if (screen_x > 0 && screen_x-mouse_x < sz/2) {
+ if (screen_y > 0 && screen_y-mouse_y < sz/2)
+ showpie= ShowPieMode.CPIE_BOT_RIGHT; //show 1/4 pie
+ else
+ showpie= ShowPieMode.HPIE_RIGHT; //show 1/2 pie
+
+ } else if (screen_y > 0 && screen_y-mouse_y < sz/2)
+ showpie= ShowPieMode.HPIE_BOTTOM; //show 1/2 pie
+
+
+ } else {
+ //if the pie is centered in the screen, don't reduce the size
+ if (PieManager.get_is_centered(pie.id)) {
+ reduce_szx= 0;
+ reduce_szy= 0;
+ }
+
+ //select the configured shape
+ //convert from radio-buttum number to ShowPieMode enum
+ switch( PieManager.get_shape_number(pie.id) ) {
+ case 1:
+ showpie= ShowPieMode.CPIE_BOT_RIGHT;
+ if (screen_x-mouse_x > sz/2)
+ reduce_szx= 0; //keep full width
+ if (screen_y-mouse_y > sz/2)
+ reduce_szy= 0; //keep full height
+ break;
+ case 2:
+ showpie= ShowPieMode.HPIE_RIGHT;
+ if (screen_x-mouse_x > sz/2)
+ reduce_szx= 0; //keep full width
+ break;
+ case 3:
+ showpie= ShowPieMode.CPIE_TOP_RIGHT;
+ if (screen_x-mouse_x > sz/2)
+ reduce_szx= 0; //keep full width
+ if (mouse_y > sz/2)
+ reduce_szy= 0; //keep full height
+ break;
+ case 4:
+ showpie= ShowPieMode.HPIE_BOTTOM;
+ if (screen_y-mouse_y > sz/2)
+ reduce_szy= 0; //keep full height
+ break;
+ case 6:
+ showpie= ShowPieMode.HPIE_TOP;
+ if (mouse_y > sz/2)
+ reduce_szy= 0; //keep full height
+ break;
+ case 7:
+ showpie= ShowPieMode.CPIE_BOT_LEFT;
+ if (mouse_x > sz/2)
+ reduce_szx= 0; //keep full width
+ if (screen_y-mouse_y > sz/2)
+ reduce_szy= 0; //keep full height
+ break;
+ case 8:
+ showpie= ShowPieMode.HPIE_LEFT;
+ if (mouse_x > sz/2)
+ reduce_szx= 0; //keep full width
+ break;
+ case 9:
+ showpie= ShowPieMode.CPIE_TOP_LEFT;
+ if (mouse_x > sz/2)
+ reduce_szx= 0; //keep full width
+ if (mouse_y > sz/2)
+ reduce_szy= 0; //keep full height
+ break;
+ }
+ }
+ //set the new show pie mode
+ set_show_mode(showpie);
+
+ //recalc size
+ sz = sz0;
+ if (this.total_slice_count > 0) {
+ sz = (int)fmax(sz0,
+ (((Config.global.theme.slice_radius + Config.global.theme.slice_gap)/tan(PI/this.total_slice_count))
+ + Config.global.theme.visible_slice_radius)*2*Config.global.theme.max_zoom);
+ }
+ //activation_range = normal pie radius + "outer" activation_range
+ this.activation_range= (int)((double)Config.global.activation_range + sz/(2*Config.global.theme.max_zoom));
+
+ int szx = 1; //full width
+ int szy = 1; //full height
+ switch(this.pie_show_mode) {
+ //half pie
+ case ShowPieMode.HPIE_LEFT:
+ szx = 0; //half width, center to the left
+ break;
+ case ShowPieMode.HPIE_RIGHT:
+ szx = 2; //half width, center to the right
+ break;
+ case ShowPieMode.HPIE_TOP:
+ szy = 0; //half height, center to the top
+ break;
+ case ShowPieMode.HPIE_BOTTOM:
+ szy = 2; //half height, center to the bottom
+ break;
+
+ //cuarter pie
+ case ShowPieMode.CPIE_TOP_LEFT:
+ szx = 0; //half width, center to the left
+ szy = 0; //half height, center to the top
+ break;
+ case ShowPieMode.CPIE_TOP_RIGHT:
+ szx = 2; //half width, center to the right
+ szy = 0; //half height, center to the top
+ break;
+ case ShowPieMode.CPIE_BOT_LEFT:
+ szx = 0; //half width, center to the left
+ szy = 2; //half height, center to the bottom
+ break;
+ case ShowPieMode.CPIE_BOT_RIGHT:
+ szx = 2; //half width, center to the right
+ szy = 2; //half height, center to the bottom
+ break;
+ }
+ if (reduce_szx == 0)
+ szx = 1; //don't reduce width
+ if (reduce_szy == 0)
+ szy = 1; //don't reduce height
+
+ int rc = (int)Config.global.theme.center_radius;
+ if (szx == 1 ) {
+ //full width
+ this.size_w = sz;
+ this.center_x = sz/2; //center position
+ } else {
+ //half width
+ this.size_w = sz/2 + rc;
+ if (szx == 0) {
+ this.center_x = rc; //center to the left
+ } else {
+ this.center_x = this.size_w-rc; //center to the right
+ }
+ }
+ if (szy == 1) {
+ //full heigth
+ this.size_h = sz;
+ this.center_y = sz/2; //center position
+ } else {
+ //half heigth
+ this.size_h = sz/2 + rc;
+ if (szy == 0) {
+ this.center_y = rc; //center to the top
+ } else {
+ this.center_y = this.size_h-rc; //center to the bottom
+ }
}
}
@@ -130,12 +423,16 @@ public class PieRenderer : GLib.Object {
/////////////////////////////////////////////////////////////////////
public void activate() {
- if (this.active_slice >= 0 && this.active_slice < this.slices.size) {
+ if (this.active_slice >= this.first_slice_idx
+ && this.active_slice < this.first_slice_idx+this.visible_slice_count) {
slices[active_slice].activate();
}
- foreach (var slice in this.slices)
- slice.fade_out();
+ //foreach (var slice in this.slices)
+ // slice.fade_out();
+ for (int i= 0; i < this.visible_slice_count; ++i) {
+ this.slices[ i+this.first_slice_idx ].fade_out();
+ }
center.fade_out();
}
@@ -145,29 +442,23 @@ public class PieRenderer : GLib.Object {
/////////////////////////////////////////////////////////////////////
public void cancel() {
- foreach (var slice in this.slices)
- slice.fade_out();
+ //foreach (var slice in this.slices)
+ // slice.fade_out();
+ for (int i= 0; i < this.visible_slice_count; ++i) {
+ this.slices[ i+this.first_slice_idx ].fade_out();
+ }
center.fade_out();
}
+
/////////////////////////////////////////////////////////////////////
/// Called when the up-key is pressed. Selects the next slice towards
/// the top.
/////////////////////////////////////////////////////////////////////
public void select_up() {
- int bottom = this.slice_count()/4;
- int top = this.slice_count()*3/4;
-
- if (this.active_slice == -1 || this.active_slice == bottom)
- this.set_highlighted_slice(top);
- else if (this.active_slice > bottom && this.active_slice < top)
- this.set_highlighted_slice(this.active_slice+1);
- else if (this.active_slice != top)
- this.set_highlighted_slice((this.active_slice-1+this.slice_count())%this.slice_count());
-
- this.key_board_control = true;
+ move_active_slice(this.up_slice_idx, this.down_slice_idx);
}
/////////////////////////////////////////////////////////////////////
@@ -176,17 +467,7 @@ public class PieRenderer : GLib.Object {
/////////////////////////////////////////////////////////////////////
public void select_down() {
- int bottom = this.slice_count()/4;
- int top = this.slice_count()*3/4;
-
- if (this.active_slice == -1 || this.active_slice == top)
- this.set_highlighted_slice(bottom);
- else if (this.active_slice > bottom && this.active_slice < top)
- this.set_highlighted_slice(this.active_slice-1);
- else if (this.active_slice != bottom)
- this.set_highlighted_slice((this.active_slice+1)%this.slice_count());
-
- this.key_board_control = true;
+ move_active_slice(this.down_slice_idx, this.up_slice_idx);
}
/////////////////////////////////////////////////////////////////////
@@ -195,17 +476,7 @@ public class PieRenderer : GLib.Object {
/////////////////////////////////////////////////////////////////////
public void select_left() {
- int left = this.slice_count()/2;
- int right = 0;
-
- if (this.active_slice == -1 || this.active_slice == right)
- this.set_highlighted_slice(left);
- else if (this.active_slice > left)
- this.set_highlighted_slice(this.active_slice-1);
- else if (this.active_slice < left)
- this.set_highlighted_slice(this.active_slice+1);
-
- this.key_board_control = true;
+ move_active_slice(this.left_slice_idx, this.right_slice_idx);
}
/////////////////////////////////////////////////////////////////////
@@ -214,17 +485,79 @@ public class PieRenderer : GLib.Object {
/////////////////////////////////////////////////////////////////////
public void select_right() {
- int left = this.slice_count()/2;
- int right = 0;
+ move_active_slice(this.right_slice_idx, this.left_slice_idx);
+ }
- if (this.active_slice == -1 || this.active_slice == left)
- this.set_highlighted_slice(right);
- else if (this.active_slice > left)
- this.set_highlighted_slice((this.active_slice+1)%this.slice_count());
- else if (this.active_slice < left && this.active_slice != right)
- this.set_highlighted_slice((this.active_slice-1+this.slice_count())%this.slice_count());
+ /////////////////////////////////////////////////////////////////////
+ /// Called when the page_up-key is pressed. Selects the next
+ /// group of slices.
+ /////////////////////////////////////////////////////////////////////
- this.key_board_control = true;
+ public void select_nextpage() {
+ if (this.first_slice_idx+this.visible_slice_count < slices.size) {
+ //advance one page
+ this.first_slice_idx += this.visible_slice_count;
+ if (this.first_slice_idx+this.visible_slice_count >= slices.size) {
+ this.visible_slice_count= slices.size - this.first_slice_idx;
+ }
+ this.reset_sclice_anim();
+ this.set_highlighted_slice(-1);
+ calc_key_navigation_pos();
+ this.key_board_control = true;
+
+ } else if (this.first_slice_idx > 0) {
+ //go to first page
+ this.first_slice_idx= 0;
+ this.reset_sclice_anim();
+ //recover the original value
+ this.visible_slice_count= this.original_visible_slice_count;
+ this.reset_sclice_anim();
+ this.set_highlighted_slice(-1);
+ calc_key_navigation_pos();
+ this.key_board_control = true;
+ }
+ }
+
+ /////////////////////////////////////////////////////////////////////
+ /// Called when the page_down-key is pressed. Selects the previous
+ /// group of slices.
+ /////////////////////////////////////////////////////////////////////
+
+ public void select_prevpage() {
+ if (this.first_slice_idx > 0) {
+ //go back one page
+ //recover the original value
+ this.visible_slice_count= this.original_visible_slice_count;
+ this.first_slice_idx -= this.visible_slice_count;
+ if (this.first_slice_idx < 0) {
+ this.first_slice_idx= 0;
+ }
+ this.reset_sclice_anim();
+ this.set_highlighted_slice(-1);
+ calc_key_navigation_pos();
+ this.key_board_control = true;
+
+ } else if (this.visible_slice_count < slices.size) {
+ //go to last page
+ int n= slices.size % this.original_visible_slice_count;
+ if (n == 0)
+ //all pages have the same number of slices
+ this.visible_slice_count= this.original_visible_slice_count;
+ else
+ //last page has less slices than previous
+ this.visible_slice_count= n;
+ this.first_slice_idx= slices.size - this.visible_slice_count;
+ this.reset_sclice_anim();
+ this.set_highlighted_slice(-1);
+ calc_key_navigation_pos();
+ this.key_board_control = true;
+ }
+ }
+
+ private void reset_sclice_anim() {
+ //reset animation values in all the new visible slices
+ for (int i= 0; i < this.visible_slice_count; ++i)
+ this.slices[ i+this.first_slice_idx ].reset_anim();
}
/////////////////////////////////////////////////////////////////////
@@ -240,41 +573,58 @@ public class PieRenderer : GLib.Object {
/////////////////////////////////////////////////////////////////////
public void draw(double frame_time, Cairo.Context ctx, int mouse_x, int mouse_y) {
- if (this.size > 0) {
- double distance = sqrt(mouse_x*mouse_x + mouse_y*mouse_y);
- double angle = 0.0;
-
- if (this.key_board_control) {
- angle = 2.0*PI*this.active_slice/(double)slice_count();
- } else {
-
- if (distance > 0) {
- angle = acos(mouse_x/distance);
- if (mouse_y < 0)
- angle = 2*PI - angle;
- }
-
- int next_active_slice = this.active_slice;
-
- if (distance < Config.global.theme.active_radius
- && this.quickaction >= 0 && this.quickaction < this.slices.size) {
+ if (this.size_w > 0) {
+ double distance = sqrt(mouse_x*mouse_x + mouse_y*mouse_y);
+ double angle = 0.0;
+ int slice_track= 0;
+
+ if (this.key_board_control) {
+ int n= this.active_slice - this.first_slice_idx;
+ angle = 2.0*PI*n/(double)this.total_slice_count + this.first_slice_angle;
+ slice_track= 1;
+ } else {
+
+ if (distance > 0) {
+ angle = acos(mouse_x/distance);
+ if (mouse_y < 0)
+ angle = 2*PI - angle;
+ }
- next_active_slice = this.quickaction;
- angle = 2.0*PI*quickaction/(double)slice_count();
- } else if (distance > Config.global.theme.active_radius && this.slice_count() > 0 && distance < Config.global.activation_range) {
- next_active_slice = (int)(angle*slices.size/(2*PI) + 0.5) % this.slice_count();
- } else {
- next_active_slice = -1;
- }
+ int next_active_slice = this.active_slice;
+
+ if (distance < Config.global.theme.active_radius
+ && this.quickaction >= this.first_slice_idx
+ && this.quickaction < this.first_slice_idx+this.visible_slice_count) {
+
+ next_active_slice = this.quickaction;
+ int n= this.quickaction - this.first_slice_idx;
+ angle = 2.0*PI*n/(double)this.total_slice_count + this.first_slice_angle;
+
+ } else if (distance > Config.global.theme.active_radius && this.total_slice_count > 0
+ && distance < this.activation_range) {
+ double a= angle-this.first_slice_angle;
+ if (a < 0)
+ a= a + 2*PI;
+ next_active_slice = (int)(a*this.total_slice_count/(2*PI) + 0.5) % this.total_slice_count;
+ if (next_active_slice >= this.visible_slice_count)
+ next_active_slice = -1;
+ else {
+ next_active_slice = next_active_slice + this.first_slice_idx;
+ slice_track= 1;
+ }
+ } else {
+ next_active_slice = -1;
+ }
- this.set_highlighted_slice(next_active_slice);
- }
+ this.set_highlighted_slice(next_active_slice);
+ }
- center.draw(frame_time, ctx, angle, distance);
+ center.draw(frame_time, ctx, angle, slice_track);
- foreach (var slice in this.slices)
- slice.draw(frame_time, ctx, angle, distance);
- }
+ for (int i= 0; i < this.visible_slice_count; ++i) {
+ this.slices[ i+this.first_slice_idx ].draw(frame_time, ctx, angle, slice_track);
+ }
+ }
}
/////////////////////////////////////////////////////////////////////
@@ -291,21 +641,215 @@ public class PieRenderer : GLib.Object {
public void set_highlighted_slice(int index) {
if (index != this.active_slice) {
- if (index >= 0 && index < this.slice_count())
+ if (index >= this.first_slice_idx && index < this.first_slice_idx+this.visible_slice_count)
this.active_slice = index;
- else if (this.quickaction >= 0)
- this.active_slice = this.quickaction;
else
this.active_slice = -1;
- SliceRenderer? active = (this.active_slice >= 0 && this.active_slice < this.slice_count()) ?
+ SliceRenderer? active = (this.active_slice >= 0 && this.active_slice < slices.size) ?
this.slices[this.active_slice] : null;
center.set_active_slice(active);
- foreach (var slice in this.slices)
- slice.set_active_slice(active);
+ for (int i= 0; i < this.visible_slice_count; ++i) {
+ this.slices[ i+this.first_slice_idx ].set_active_slice(active);
+ }
+ }
+ }
+
+ private void set_show_mode(ShowPieMode show_mode) {
+ //The index of the first visible slice
+ this.first_slice_idx= 0;
+ //Angular position of the first visible slice
+ this.first_slice_angle= 0;
+
+ int mult= 1;
+ switch(show_mode) {
+ //half pie
+ case ShowPieMode.HPIE_LEFT:
+ mult= 2;
+ this.first_slice_angle= -PI/2;
+ break;
+ case ShowPieMode.HPIE_RIGHT:
+ mult= 2;
+ this.first_slice_angle= PI/2;
+ break;
+ case ShowPieMode.HPIE_TOP:
+ mult= 2;
+ break;
+ case ShowPieMode.HPIE_BOTTOM:
+ this.first_slice_angle= PI;
+ mult= 2;
+ break;
+
+ //cuarter pie
+ case ShowPieMode.CPIE_TOP_LEFT:
+ mult= 4;
+ break;
+ case ShowPieMode.CPIE_TOP_RIGHT:
+ this.first_slice_angle= PI/2;
+ mult= 4;
+ break;
+ case ShowPieMode.CPIE_BOT_LEFT:
+ this.first_slice_angle= -PI/2;
+ mult= 4;
+ break;
+ case ShowPieMode.CPIE_BOT_RIGHT:
+ this.first_slice_angle= PI;
+ mult= 4;
+ break;
+
+ default: //ShowPieMode.FULL_PIE or invalid values
+ show_mode= ShowPieMode.FULL_PIE;
+ break;
+ }
+ this.pie_show_mode= show_mode;
+ //limit the number of visible slices
+ int maxview= this.max_visible_slices / mult;
+ //Number of visible slices
+ this.visible_slice_count= (int)fmin(slices.size, maxview);
+ //Number of slices in full pie (visible or not)
+ this.total_slice_count= this.visible_slice_count*mult;
+ if (mult > 1 && slices.size > 1) {
+ this.total_slice_count -= mult;
}
+
+ //keep a copy of the original value since page up/down change it
+ original_visible_slice_count= visible_slice_count;
+
+ calc_key_navigation_pos();
+ }
+
+ private void calc_key_navigation_pos() {
+ //calc slices index for keyboard navigation
+
+ int a= this.first_slice_idx;
+ int b= this.first_slice_idx + this.visible_slice_count/4;
+ int c= this.first_slice_idx + this.visible_slice_count/2;
+ int d= this.first_slice_idx + (this.visible_slice_count*3)/4;
+ int e= this.first_slice_idx + this.visible_slice_count -1;
+ switch(this.pie_show_mode) {
+ //half pie
+ case ShowPieMode.HPIE_LEFT:
+ this.up_slice_idx= a;
+ this.right_slice_idx= c;
+ this.down_slice_idx= e;
+ this.left_slice_idx= -1; //no left slice, go up instead
+ break;
+ case ShowPieMode.HPIE_RIGHT:
+ this.down_slice_idx= a;
+ this.left_slice_idx= c;
+ this.up_slice_idx= e;
+ this.right_slice_idx= -1; //no right slice, go down instead
+ break;
+ case ShowPieMode.HPIE_TOP:
+ this.right_slice_idx= a;
+ this.down_slice_idx= c;
+ this.left_slice_idx= e;
+ this.up_slice_idx= -1; //no up slice, go left instead
+ break;
+ case ShowPieMode.HPIE_BOTTOM:
+ this.left_slice_idx= a;
+ this.up_slice_idx= c;
+ this.right_slice_idx= e;
+ this.down_slice_idx= -1; //no down slice, go right instead
+ break;
+
+ //cuarter pie
+ case ShowPieMode.CPIE_TOP_LEFT:
+ this.right_slice_idx= a;
+ this.down_slice_idx= e;
+ this.up_slice_idx= -1; //no up slice, go right instead
+ this.left_slice_idx= -1; //no left slice, go down instead
+ break;
+ case ShowPieMode.CPIE_TOP_RIGHT:
+ this.down_slice_idx= a;
+ this.left_slice_idx= e;
+ this.up_slice_idx= -1; //no up slice, go left instead
+ this.right_slice_idx= -1; //no righ slice, go down instead
+ break;
+ case ShowPieMode.CPIE_BOT_LEFT:
+ this.up_slice_idx= a;
+ this.right_slice_idx= e;
+ this.down_slice_idx= -1; //no down slice, go right instead
+ this.left_slice_idx= -1; //no left slice, go up instead
+ break;
+ case ShowPieMode.CPIE_BOT_RIGHT:
+ this.left_slice_idx= a;
+ this.up_slice_idx= e;
+ this.down_slice_idx= -1; //no down slice, go left instead
+ this.right_slice_idx= -1; //no right slice, go up instead
+ break;
+
+ default: //ShowPieMode.FULL_PIE or invalid values
+ this.right_slice_idx= a;
+ this.down_slice_idx= b;
+ this.left_slice_idx= c;
+ this.up_slice_idx= d;
+ break;
+ }
+ }
+
+
+ /////////////////////////////////////////////////////////////////////
+ /// keyboard navigation helper
+ /// move current position one slice towards the given extreme
+ /////////////////////////////////////////////////////////////////////
+
+ private void move_active_slice(int extreme, int other_extreme ) {
+ int pos= this.active_slice;
+
+ if (pos < 0 || pos == extreme) {
+ //no actual position or allready at the extreme
+ pos= extreme; //go to the extreme pos
+
+ } else if (extreme == -1) {
+ //the extreme was eaten, just go away from the other_extreme
+ if (pos > other_extreme || other_extreme == 0) {
+ if (pos < this.visible_slice_count+this.first_slice_idx-1)
+ pos++;
+ } else if (pos > this.first_slice_idx)
+ pos--;
+
+ } else if (other_extreme == -1) {
+ //the other_extreme was eaten, just get closer to the extreme
+ if (pos < extreme)
+ pos++;
+ else if (pos > extreme)
+ pos--;
+
+ } else if (pos == other_extreme) {
+ //both extremes are present
+ //jump quickly form one extreme to the other
+ pos= extreme; //go to the extreme pos
+
+ } else {
+ //both extremes are present
+ //add or substract 1 to position in a circular manner
+ if (extreme > other_extreme) {
+ if (pos > other_extreme && pos < extreme)
+ //other_extreme < pos < extreme
+ pos= pos+1;
+ else
+ pos= pos-1;
+ } else {
+ if (pos > extreme && pos < other_extreme)
+ //extreme < pos < other_extreme
+ pos= pos-1;
+ else
+ pos= pos+1;
+ }
+
+ if (pos < this.first_slice_idx)
+ pos= this.visible_slice_count-1+this.first_slice_idx;
+
+ if (pos >= this.visible_slice_count+this.first_slice_idx)
+ pos= this.first_slice_idx;
+ }
+
+ this.set_highlighted_slice(pos);
+
+ this.key_board_control = true;
}
}
diff --git a/src/renderers/pieWindow.vala b/src/renderers/pieWindow.vala
index da346dd..4d5d35a 100644..100755
--- a/src/renderers/pieWindow.vala
+++ b/src/renderers/pieWindow.vala
@@ -1,19 +1,19 @@
-/*
-Copyright (c) 2011 by Simon Schneegans
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option)
-any later version.
-
-This program 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 General Public License for
-more details.
-
-You should have received a copy of the GNU General Public License along with
-this program. If not, see <http://www.gnu.org/licenses/>.
-*/
+/////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2011-2015 by Simon Schneegans
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or (at
+// your option) any later version.
+//
+// This program 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
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+/////////////////////////////////////////////////////////////////////////
using GLib.Math;
@@ -45,6 +45,31 @@ public class PieWindow : Gtk.Window {
public Image background { get; private set; default=null; }
/////////////////////////////////////////////////////////////////////
+ /// The background image position and size.
+ /////////////////////////////////////////////////////////////////////
+
+ private int back_x;
+ private int back_y;
+ private int back_sz_x;
+ private int back_sz_y;
+
+ /////////////////////////////////////////////////////////////////////
+ /// Some panels moves the window after it was realized.
+ /// This value set the maximum allowed panel height or width.
+ /// (how many pixels the window could be moved in every direction
+ /// from the screen borders towards the center)
+ /////////////////////////////////////////////////////////////////////
+
+ private int panel_sz = 64;
+
+ /////////////////////////////////////////////////////////////////////
+ /// This value set the maximum allowed mouse movement in pixels
+ /// from the capture to the show point in every direction.
+ /////////////////////////////////////////////////////////////////////
+
+ private int mouse_move = 30;
+
+ /////////////////////////////////////////////////////////////////////
/// The owned renderer.
/////////////////////////////////////////////////////////////////////
@@ -97,11 +122,12 @@ public class PieWindow : Gtk.Window {
this.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK |
Gdk.EventMask.KEY_RELEASE_MASK |
Gdk.EventMask.KEY_PRESS_MASK |
- Gdk.EventMask.POINTER_MOTION_MASK);
+ Gdk.EventMask.POINTER_MOTION_MASK |
+ Gdk.EventMask.SCROLL_MASK );
// activate on left click
this.button_release_event.connect ((e) => {
- if (e.button == 1 || this.renderer.turbo_mode) this.activate_slice();
+ if (e.button == 1 || PieManager.get_is_turbo(this.renderer.id)) this.activate_slice();
return true;
});
@@ -124,7 +150,7 @@ public class PieWindow : Gtk.Window {
// activate on key release if turbo_mode is enabled
this.key_release_event.connect((e) => {
last_key = 0;
- if (this.renderer.turbo_mode)
+ if (PieManager.get_is_turbo(this.renderer.id))
this.activate_slice();
else
this.handle_key_release(e.keyval);
@@ -142,6 +168,15 @@ public class PieWindow : Gtk.Window {
FocusGrabber.grab(this.get_window(), true, true, false);
});
+ this.scroll_event.connect((e) => {
+ if (e.direction == Gdk.ScrollDirection.UP)
+ this.renderer.select_prevpage();
+
+ else if (e.direction == Gdk.ScrollDirection.DOWN)
+ this.renderer.select_nextpage();
+ return true;
+ });
+
// draw the pie on expose
this.draw.connect(this.draw_window);
}
@@ -153,7 +188,7 @@ public class PieWindow : Gtk.Window {
public void load_pie(Pie pie) {
this.renderer.load_pie(pie);
this.set_window_position(pie);
- this.set_size_request(renderer.size, renderer.size);
+ this.set_size_request(renderer.size_w, renderer.size_h);
}
/////////////////////////////////////////////////////////////////////
@@ -162,13 +197,56 @@ public class PieWindow : Gtk.Window {
public void open() {
this.realize();
-
// capture the background image if there is no compositing
if (!this.has_compositing) {
- int x, y, width, height;
- this.get_position(out x, out y);
- this.get_size(out width, out height);
- this.background = new Image.capture_screen(x, y, width+1, height+1);
+ this.get_position(out this.back_x, out this.back_y);
+ this.get_size(out this.back_sz_x, out this.back_sz_y);
+ this.back_sz_x++;
+ this.back_sz_y++;
+
+ int screenx= Gdk.Screen.width();
+ int screeny= Gdk.Screen.height();
+
+ //allow some window movement from the screen borders
+ //(some panels moves the window after it was realized)
+ int dx = this.panel_sz - this.back_x;
+ if (dx > 0)
+ this.back_sz_x += dx;
+ dx = this.panel_sz - (screenx - this.back_x - this.back_sz_x +1);
+ if (dx > 0) {
+ this.back_sz_x += dx;
+ this.back_x -= dx;
+ }
+
+ int dy = this.panel_sz - this.back_y;
+ if (dy > 0)
+ this.back_sz_y += dy;
+ dy = this.panel_sz - (screeny - this.back_y - this.back_sz_y +1);
+ if (dy > 0) {
+ this.back_sz_y += dy;
+ this.back_y -= dy;
+ }
+
+ //also tolerate some mouse movement
+ this.back_x -= this.mouse_move;
+ this.back_sz_x += this.mouse_move*2;
+ this.back_y -= this.mouse_move;
+ this.back_sz_y += this.mouse_move*2;
+
+ //make sure we don't go outside the screen
+ if (this.back_x < 0) {
+ this.back_sz_x += this.back_x;
+ this.back_x = 0;
+ }
+ if (this.back_y < 0) {
+ this.back_sz_y += this.back_y;
+ this.back_y = 0;
+ }
+ if (this.back_x + this.back_sz_x > screenx)
+ this.back_sz_x = screenx - this.back_x;
+ if (this.back_y + this.back_sz_y > screeny)
+ this.back_sz_y = screeny - this.back_y;
+ this.background = new Image.capture_screen(this.back_x, this.back_y, this.back_sz_x, this.back_sz_y);
}
// capture the input focus
@@ -179,11 +257,20 @@ public class PieWindow : Gtk.Window {
this.timer.start();
this.queue_draw();
+ bool warp_pointer = PieManager.get_is_warp(this.renderer.id);
+
// the main draw loop
GLib.Timeout.add((uint)(1000.0/Config.global.refresh_rate), () => {
if (this.closed)
return false;
+ if (warp_pointer) {
+ warp_pointer = false;
+ int x, y;
+ this.get_center_pos(out x, out y);
+ this.set_mouse_position(x, y);
+ }
+
this.queue_draw();
return this.visible;
});
@@ -194,12 +281,46 @@ public class PieWindow : Gtk.Window {
/////////////////////////////////////////////////////////////////////
public void get_center_pos(out int out_x, out int out_y) {
- int x=0, y=0, width=0, height=0;
+ int x=0, y=0; //width=0, height=0;
this.get_position(out x, out y);
- this.get_size(out width, out height);
+ out_x = x + renderer.center_x;
+ out_y = y + renderer.center_y;
+ }
- out_x = x + width/2;
- out_y = y + height/2;
+ /////////////////////////////////////////////////////////////////////
+ /// Gets the absolute position of the mouse pointer.
+ /////////////////////////////////////////////////////////////////////
+
+ private void get_mouse_position(out int mx, out int my) {
+ // get the mouse position
+ mx = 0;
+ my = 0;
+ Gdk.ModifierType mask;
+
+ var display = Gdk.Display.get_default();
+ var manager = display.get_device_manager();
+ GLib.List<weak Gdk.Device?> list = manager.list_devices(Gdk.DeviceType.MASTER);
+
+ foreach(var device in list) {
+ if (device.input_source != Gdk.InputSource.KEYBOARD) {
+ this.get_window().get_device_position(device, out mx, out my, out mask);
+ }
+ }
+ }
+
+ /////////////////////////////////////////////////////////////////////
+ /// Sets the absolute position of the mouse pointer.
+ /////////////////////////////////////////////////////////////////////
+
+ private void set_mouse_position(int mx, int my) {
+ var display = Gdk.Display.get_default();
+ var manager = display.get_device_manager();
+ GLib.List<weak Gdk.Device?> list = manager.list_devices(Gdk.DeviceType.MASTER);
+ foreach(var device in list) {
+ if (device.input_source != Gdk.InputSource.KEYBOARD) {
+ device.warp(Gdk.Screen.get_default(), mx, my);
+ }
+ }
}
/////////////////////////////////////////////////////////////////////
@@ -213,35 +334,34 @@ public class PieWindow : Gtk.Window {
ctx.paint();
ctx.set_operator (Cairo.Operator.OVER);
} else {
+ //correct the background position if the window was moved
+ //since the background image was captured
+ int x, y;
+ this.get_position(out x, out y);
+ int dx = this.back_x - x;
+ int dy = this.back_y - y;
+ ctx.save();
+ ctx.translate(dx, dy);
ctx.set_operator (Cairo.Operator.OVER);
ctx.set_source_surface(background.surface, -1, -1);
ctx.paint();
+ ctx.restore();
}
// align the context to the center of the PieWindow
- ctx.translate(this.width_request*0.5, this.height_request*0.5);
+ ctx.translate(this.renderer.center_x, this.renderer.center_y);
// get the mouse position
- double mouse_x = 0.0, mouse_y = 0.0;
- Gdk.ModifierType mask;
-
- var display = Gdk.Display.get_default();
- var manager = display.get_device_manager();
- GLib.List<weak Gdk.Device?> list = manager.list_devices(Gdk.DeviceType.MASTER);
-
- foreach(var device in list) {
- if (device.input_source != Gdk.InputSource.KEYBOARD) {
- this.get_window().get_device_position_double(device, out mouse_x, out mouse_y, out mask);
- }
- }
+ int mouse_x, mouse_y;
+ get_mouse_position( out mouse_x, out mouse_y );
// store the frame time
double frame_time = this.timer.elapsed();
this.timer.reset();
// render the Pie
- this.renderer.draw(frame_time, ctx, (int)(mouse_x - this.width_request*0.5),
- (int)(mouse_y - this.height_request*0.5));
+ this.renderer.draw(frame_time, ctx, mouse_x - (int)this.renderer.center_x,
+ mouse_y - (int)this.renderer.center_y);
return true;
}
@@ -309,11 +429,15 @@ public class PieWindow : Gtk.Window {
private void handle_key_press(uint key) {
if (Gdk.keyval_name(key) == "Escape") this.cancel();
else if (Gdk.keyval_name(key) == "Return") this.activate_slice();
- else if (!this.renderer.turbo_mode) {
+ else if (!PieManager.get_is_turbo(this.renderer.id)) {
if (Gdk.keyval_name(key) == "Up") this.renderer.select_up();
else if (Gdk.keyval_name(key) == "Down") this.renderer.select_down();
else if (Gdk.keyval_name(key) == "Left") this.renderer.select_left();
else if (Gdk.keyval_name(key) == "Right") this.renderer.select_right();
+ else if (Gdk.keyval_name(key) == "Page_Down") this.renderer.select_nextpage();
+ else if (Gdk.keyval_name(key) == "Page_Up") this.renderer.select_prevpage();
+ else if (Gdk.keyval_name(key) == "Tab") this.renderer.select_nextpage();
+ else if (Gdk.keyval_name(key) == "ISO_Left_Tab") this.renderer.select_prevpage();
else if (Gdk.keyval_name(key) == "Alt_L") this.renderer.show_hotkeys = true;
else {
int index = -1;
@@ -342,7 +466,7 @@ public class PieWindow : Gtk.Window {
/////////////////////////////////////////////////////////////////////
private void handle_key_release(uint key) {
- if (!this.renderer.turbo_mode) {
+ if (!PieManager.get_is_turbo(this.renderer.id)) {
if (Gdk.keyval_name(key) == "Alt_L") this.renderer.show_hotkeys = false;
}
}
diff --git a/src/renderers/sliceRenderer.vala b/src/renderers/sliceRenderer.vala
index 2ecf7c4..862e2a5 100644
--- a/src/renderers/sliceRenderer.vala
+++ b/src/renderers/sliceRenderer.vala
@@ -1,19 +1,19 @@
-/*
-Copyright (c) 2011 by Simon Schneegans
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the Free
-Software Foundation, either version 3 of the License, or (at your option)
-any later version.
-
-This program 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 General Public License for
-more details.
-
-You should have received a copy of the GNU General Public License along with
-this program. If not, see <http://www.gnu.org/licenses/>.
-*/
+/////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2011-2015 by Simon Schneegans
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or (at
+// your option) any later version.
+//
+// This program 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
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+/////////////////////////////////////////////////////////////////////////
using GLib.Math;
@@ -94,7 +94,14 @@ public class SliceRenderer : GLib.Object {
public SliceRenderer(PieRenderer parent) {
this.parent = parent;
+ this.reset_anim();
+ }
+ /////////////////////////////////////////////////////////////////////
+ /// Put all AnimatedValues in their initial values
+ /////////////////////////////////////////////////////////////////////
+
+ public void reset_anim() {
this.fade = new AnimatedValue.linear(0.0, 0.0, Config.global.theme.transition_time);
this.wobble = new AnimatedValue.linear(0.0, 0.0, Config.global.theme.transition_time);
this.alpha = new AnimatedValue.linear(0.0, 1.0, Config.global.theme.fade_in_time);
@@ -147,7 +154,7 @@ public class SliceRenderer : GLib.Object {
}
/////////////////////////////////////////////////////////////////////
- /// Activaes the Action of this slice.
+ /// Activates the Action of this slice.
/////////////////////////////////////////////////////////////////////
public void activate() {
@@ -189,7 +196,7 @@ public class SliceRenderer : GLib.Object {
/// Draws all layers of the slice.
/////////////////////////////////////////////////////////////////////
- public void draw(double frame_time, Cairo.Context ctx, double angle, double distance) {
+ public void draw(double frame_time, Cairo.Context ctx, double angle, int slice_track) {
// update the AnimatedValues
this.scale.update(frame_time);
@@ -199,16 +206,23 @@ public class SliceRenderer : GLib.Object {
this.fade_rotation.update(frame_time);
this.wobble.update(frame_time);
- double direction = 2.0 * PI * position/parent.slice_count() + this.fade_rotation.val;
- double max_scale = 1.0/Config.global.theme.max_zoom;
+ double direction = 2.0 * PI * (position-parent.first_slice_idx)/parent.total_slice_count
+ + parent.first_slice_angle + this.fade_rotation.val;
+ double max_scale = 1.0/Config.global.theme.max_zoom;
double diff = fabs(angle-direction);
- if (diff > PI)
- diff = 2 * PI - diff;
+ if (diff > 2 * PI) {
+ diff = diff - 2 * PI;
+ }
+
+ if (diff > PI) {
+ diff = 2 * PI - diff;
+ }
+
- active = ((parent.active_slice >= 0) && (diff < PI/parent.slice_count()));
+ active = ((parent.active_slice >= 0) && (diff < PI/parent.total_slice_count));
- if (parent.active_slice >= 0) {
+ if (slice_track != 0) {
double wobble = Config.global.theme.wobble*diff/PI*(1-diff/PI);
if ((direction < angle && direction > angle - PI) || direction > PI+angle) {
this.wobble.reset_target(-wobble, Config.global.theme.transition_time*0.5);
@@ -228,7 +242,7 @@ public class SliceRenderer : GLib.Object {
- max_scale = (parent.active_slice >= 0 ? max_scale : 1.0/Config.global.theme.max_zoom);
+ max_scale = (slice_track != 0 ? max_scale : 1.0/Config.global.theme.max_zoom);
if (fabs(this.scale.end - max_scale) > Config.global.theme.max_zoom*0.005)
this.scale.reset_target(max_scale, Config.global.theme.transition_time);
@@ -240,9 +254,9 @@ public class SliceRenderer : GLib.Object {
// increase radius if there are many slices in a pie
if (atan((Config.global.theme.slice_radius+Config.global.theme.slice_gap)
- /(radius/Config.global.theme.max_zoom)) > PI/parent.slice_count()) {
+ /(radius/Config.global.theme.max_zoom)) > PI/parent.total_slice_count) {
radius = (Config.global.theme.slice_radius+Config.global.theme.slice_gap)
- /tan(PI/parent.slice_count())*Config.global.theme.max_zoom;
+ /tan(PI/parent.total_slice_count)*Config.global.theme.max_zoom;
}
// transform the context