diff options
author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2015-04-18 15:43:01 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2015-04-18 15:43:01 +0200 |
commit | dd33244267d4c4be09521937de8b0e05ff216a5c (patch) | |
tree | 4d1f734c1f55a6dcceb3d0bd5373c838e4667d3f /src/renderers | |
parent | b1f493d50d3d891f35033dbf6f4a49ab5bcd00cf (diff) | |
parent | 84a27086bbd9f493128b354300f9c77ccb32a56b (diff) |
Merge tag 'upstream/0.6.0'
Upstream version 0.6.0
Diffstat (limited to 'src/renderers')
-rw-r--r-- | src/renderers/centerRenderer.vala | 214 | ||||
-rw-r--r-- | src/renderers/pieRenderer.vala | 768 | ||||
-rwxr-xr-x[-rw-r--r--] | src/renderers/pieWindow.vala | 216 | ||||
-rw-r--r-- | src/renderers/sliceRenderer.vala | 68 |
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 |