diff --git a/.github/workflows/generate-release-notes.yml b/.github/workflows/generate-release-notes.yml
new file mode 100644
index 00000000000..cb2801a1076
--- /dev/null
+++ b/.github/workflows/generate-release-notes.yml
@@ -0,0 +1,50 @@
+name: Generate Release Notes
+
+on:
+ # This workflow gets triggered manually
+ workflow_dispatch:
+ inputs:
+ new-release-tag:
+ description: 'Tag name of the new release'
+ required: true
+ type: string
+ default: 'e.g., v1.1 or v2.0'
+ previous-release-reference:
+ description: 'Tag name of the previous release or the commit SHA right before the first commit in the new release'
+ required: true
+ type: string
+ default: 'e.g., v1.0 or 2f4a6b2'
+ release-notes-source:
+ description: 'Release Notes Source'
+ required: true
+ type: choice
+ options:
+ - Commit Messages
+ - Pull Requests
+ default: 'Pull Requests'
+ pr-release-notes-mode:
+ description: 'Release Notes Mode (only affects release notes if you chose source as pull requests)'
+ required: false
+ type: choice
+ options:
+ - Short
+ - Full
+ default: 'Full'
+
+jobs:
+ generate-release-notes:
+ name: Generate Release Notes
+ runs-on: ubuntu-latest
+ steps:
+ - name: Use The Release Notes Manager Action
+ uses: Ahmed-Khaled-dev/release-notes-manager@v1
+ env:
+ # secrets.GITHUB_TOKEN is automatically generated by GitHub for each workflow run
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ action-type: release
+ new-release-tag: ${{ inputs.new-release-tag }}
+ previous-release-reference: ${{ inputs.previous-release-reference }}
+ release-notes-source: ${{ inputs.release-notes-source }}
+ pr-release-notes-mode: ${{ inputs.pr-release-notes-mode }}
+ github-repository: ${{ github.repository }}
diff --git a/.github/workflows/show-pr-change-note.yml b/.github/workflows/show-pr-change-note.yml
new file mode 100644
index 00000000000..d28a9cba9b4
--- /dev/null
+++ b/.github/workflows/show-pr-change-note.yml
@@ -0,0 +1,20 @@
+name: Show Pull Request Change Note
+
+on:
+ pull_request:
+ types: [opened, edited]
+
+jobs:
+ show-pull-request-change-note:
+ name: Show Pull Request Change Note
+ runs-on: ubuntu-latest
+ steps:
+ - name: Use The Release Notes Manager Action
+ uses: Ahmed-Khaled-dev/release-notes-manager@v1
+ env:
+ # secrets.GITHUB_TOKEN is automatically generated by GitHub for each workflow run
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ action-type: pr
+ pull-request-number: ${{ github.event.pull_request.number }}
+ pull-request-trigger-event: ${{ github.event.action }}
diff --git a/synfig-studio/src/gui/canvasview.cpp b/synfig-studio/src/gui/canvasview.cpp
index de3f26e1670..298213112e0 100644
--- a/synfig-studio/src/gui/canvasview.cpp
+++ b/synfig-studio/src/gui/canvasview.cpp
@@ -1259,6 +1259,16 @@ CanvasView::create_right_toolbar()
right_toolbar->append(*snap_grid);
}
+ {
+ Gtk::ToggleToolButton *show_ruler = Gtk::manage(new Gtk::ToggleToolButton());
+ show_ruler->signal_toggled().connect( [this](){
+ work_area->show_ruler();
+ } );
+ show_ruler->show();
+ displaybar->append(*show_ruler);
+
+ }
+
{ // Show guide toggle button
show_guides = Gtk::manage(new Gtk::ToggleToolButton());
show_guides->set_active(work_area->get_show_guides());
diff --git a/synfig-studio/src/gui/docks/dock_timetrack2.cpp.autosave b/synfig-studio/src/gui/docks/dock_timetrack2.cpp.autosave
new file mode 100644
index 00000000000..61079df0a86
--- /dev/null
+++ b/synfig-studio/src/gui/docks/dock_timetrack2.cpp.autosave
@@ -0,0 +1,355 @@
+/* === S Y N F I G ========================================================= */
+/*! \file docks/dock_timetrack2.cpp
+** \brief Dock to displaying layer parameters timetrack
+**
+** \legal
+** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
+** ......... ... 2020 Rodolfo Ribeiro Gomes
+**
+** This file is part of Synfig.
+**
+** Synfig 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 2 of the License, or
+** (at your option) any later version.
+**
+** Synfig 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 Synfig. If not, see .
+** \endlegal
+*/
+
+#ifdef USING_PCH
+# include "pch.h"
+#else
+#ifdef HAVE_CONFIG_H
+# include
+#endif
+
+#include "dock_timetrack2.h"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#endif
+
+using namespace studio;
+
+Dock_Timetrack2::Dock_Timetrack2()
+ : Dock_CanvasSpecific("timetrack", _("Timetrack"), Gtk::StockID("synfig-timetrack")),
+ current_widget_timetrack(nullptr)
+{
+ set_use_scrolled(false);
+
+ widget_kf_list.set_hexpand();
+ widget_kf_list.show();
+ widget_timeslider.set_hexpand();
+ widget_timeslider.show();
+
+ vscrollbar.set_vexpand();
+ vscrollbar.set_hexpand(false);
+ vscrollbar.set_orientation(Gtk::ORIENTATION_VERTICAL);
+ vscrollbar.show();
+ hscrollbar.set_hexpand();
+ hscrollbar.show();
+
+ setup_tool_palette();
+ tool_palette.show_all();
+
+ grid.set_column_homogeneous(false);
+ grid.set_row_homogeneous(false);
+ // for letting user click/drag waypoint or keyframe mark of time zero
+ grid.set_margin_start(2);
+ grid.set_margin_end(2);
+
+ add(grid);
+}
+
+void Dock_Timetrack2::init_canvas_view_vfunc(etl::loose_handle canvas_view)
+{
+ Widget_Timetrack *widget_timetrack = new Widget_Timetrack();
+ widget_timetrack->use_canvas_view(canvas_view);
+ widget_timetrack->show();
+ widget_timetrack->set_hexpand(true);
+ widget_timetrack->set_vexpand(true);
+ widget_timetrack->set_valign(Gtk::ALIGN_FILL);
+
+ canvas_view->set_ext_widget(get_name(), widget_timetrack);
+
+ // sync with Parameters Dock
+ // scrolling
+ vscrollbar.set_adjustment(widget_timetrack->get_range_adjustment());
+ canvas_view->get_adjustment_group("params")->add(vscrollbar.get_adjustment());
+ // TreeView header
+ studio::LayerTree *tree_layer = dynamic_cast(canvas_view->get_ext_widget("layers_cmp") );
+ assert(tree_layer);
+ tree_layer->signal_param_tree_header_height_changed().connect(
+ sigc::mem_fun(*this, &studio::Dock_Timetrack2::on_update_header_height)
+ );
+ //could be useful mod adham
+ widget_timetrack->signal_waypoint_clicked().connect(sigc::mem_fun(*this, &Dock_Timetrack2::on_widget_timetrack_waypoint_clicked));
+
+ widget_timetrack->signal_waypoint_double_clicked().connect(sigc::mem_fun(*this, &Dock_Timetrack2::on_widget_timetrack_waypoint_double_clicked));
+
+ widget_timetrack->signal_action_state_changed().connect(sigc::mem_fun(*this, &Dock_Timetrack2::update_tool_palette_action));
+}
+
+void Dock_Timetrack2::changed_canvas_view_vfunc(etl::loose_handle canvas_view)
+{
+ const std::vector children = grid.get_children();
+ for (Gtk::Widget * widget : children) {
+ // CanvasView and Dock_Timetrack2 will delete widgets when needed
+ grid.remove(*widget);
+ }
+
+ if( !canvas_view ) {
+ widget_kf_list.set_time_model( etl::handle() );
+ widget_kf_list.set_canvas_interface( etl::loose_handle() );
+
+ widget_timeslider.set_canvas_view( CanvasView::Handle() );
+
+ current_widget_timetrack = nullptr; // deleted by its studio::CanvasView::~CanvasView()
+
+ hscrollbar.unset_adjustment();
+
+ tool_palette.hide();
+ } else {
+ widget_kf_list.set_time_model(canvas_view->time_model());
+ widget_kf_list.set_canvas_interface(canvas_view->canvas_interface());
+
+ widget_timeslider.set_canvas_view(canvas_view);
+
+ current_widget_timetrack = dynamic_cast( canvas_view->get_ext_widget(get_name()) );
+ current_widget_timetrack->set_size_request(100, 100);
+ current_widget_timetrack->set_hexpand(true);
+ current_widget_timetrack->set_vexpand(true);
+
+ hscrollbar.set_adjustment(canvas_view->time_model()->scroll_time_adjustment());
+
+ update_tool_palette_action();
+ tool_palette.show();
+
+ grid.attach(widget_kf_list, 0, 0, 1, 1);
+ grid.attach(widget_timeslider, 0, 1, 1, 1);
+ grid.attach(*current_widget_timetrack, 0, 2, 1, 1);
+ grid.attach(hscrollbar, 0, 4, 2, 1);
+ grid.attach(vscrollbar, 1, 0, 1, 4);
+ grid.attach(tool_palette, 2, 0, 1, 4);
+ grid.show();
+ }
+
+}
+
+void Dock_Timetrack2::on_update_header_height(int height)
+{
+ int w = 0, h = 0;
+ widget_kf_list.get_size_request(w, h);
+ int ts_height = std::max(1, height - h);
+
+ widget_timeslider.get_size_request(w, h);
+ if (h != ts_height)
+ widget_timeslider.set_size_request(-1, ts_height);
+}
+
+void Dock_Timetrack2::on_widget_timetrack_waypoint_clicked(synfigapp::ValueDesc value_desc, std::set> waypoint_set, int button)
+{
+ if (button != 3)
+ return;
+ button = 2;
+ CanvasView::LooseHandle canvas_view = get_canvas_view();
+ if (canvas_view)
+ canvas_view->on_waypoint_clicked_canvasview(value_desc, waypoint_set, button);
+
+}
+
+void Dock_Timetrack2::on_widget_timetrack_waypoint_double_clicked(synfigapp::ValueDesc value_desc, std::set > waypoint_set, int button)
+{
+ if (button != 1)
+ return;
+ button = -1;
+ CanvasView::LooseHandle canvas_view = get_canvas_view();
+ if (canvas_view)
+ canvas_view->on_waypoint_clicked_canvasview(value_desc, waypoint_set, button);
+}
+
+
+void Dock_Timetrack2::setup_tool_palette()
+{
+ Gtk::ToolItemGroup *tool_item_group = Gtk::manage(new Gtk::ToolItemGroup()); //to make the tool item group
+ gtk_tool_item_group_set_label(tool_item_group->gobj(), nullptr); //setting the prev.'s label
+ struct ActionButtonInfo { //holds strings used later and action_state
+ std::string name;
+ std::string tooltip;
+ std::string shortcut;
+ Widget_Timetrack::ActionState action_state ;
+ };
+
+ const std::vector tools_info { //setting up the tools info thing it contains name tooltip sjortcut action state
+ {"synfig-smooth_move", _("Move waypoints\n\nSelect waypoints and drag them along the timetrack."),
+ std::string(""), Widget_Timetrack::ActionState::MOVE},
+ {"synfig-duplicate", _("Duplicate waypoints\n\nAfter selecting waypoints, drag to duplicate them and place them in another time point."),
+ _("Shift"), Widget_Timetrack::ActionState::COPY},
+ {"synfig-scale", _("Scale waypoints\n\nAfter selecting more than one waypoint, drag them to change their timepoint regarding current time."),
+// This should be a function like get_key_name() to be reused
+#ifdef __APPLE__
+ _("Option"),
+#else
+ _("Alt"),
+#endif
+ Widget_Timetrack::ActionState::SCALE},
+// {"synfig-interpolate", _(" "),]
+// std::string(""), Widget_Timetrack::ActionState::INTERPOLATE}
+ };
+
+ //loop to make tool buttons commentmohamed
+ Gtk::RadioButtonGroup button_group; // the radio group
+ for (const auto & tool_info : tools_info) {
+ const std::string &name = tool_info.name; //for getting the name string
+ std::string tooltip = tool_info.tooltip; // getting tool tip string
+ const std::string &shortcut = tool_info.shortcut; // get shortcut string
+ Widget_Timetrack::ActionState action_state = tool_info.action_state;
+
+ Gtk::StockItem stock_item; // declare a stock item
+ Gtk::Stock::lookup(Gtk::StockID(name),stock_item); // config stock item somehow
+
+ Gtk::RadioToolButton *tool_button = manage(new Gtk::RadioToolButton( //2 params 1- image the image widget 2- label
+ *manage(new Gtk::Image( // 2 params 1-stock id 2- icon size
+ stock_item.get_stock_id(),
+ Gtk::IconSize::from_name("synfig-small_icon_16x16") )),
+ stock_item.get_label() ));
+ tool_button->set_name(Widget_Timetrack::get_action_state_name(action_state));//could be a reason why there is seg
+ if (!shortcut.empty()) {
+ std::string shortcut_text = _("Shortcut: ") + shortcut;
+ tooltip += "\n\n" + shortcut_text;
+ }
+ tool_button->set_tooltip_text(tooltip);
+ tool_button->set_group(button_group); // for putting them in their respective radio group
+ tool_button->signal_toggled().connect(sigc::track_obj([this, tool_button, action_state](){
+ if (tool_button->get_active())
+ current_widget_timetrack->set_action_state(action_state);
+ }, *this));
+ action_button_map[tool_button->get_name()] = tool_button;
+ tool_item_group->add(*tool_button); //used to add a Gtk Radio tool button to the tool item group
+ }
+ //seperator prototype
+ // 1- ceonversion from c obj
+ /*GtkToolItem *cseperator = gtk_separator_tool_item_new();
+ Gtk::ToolItem *seperator = Glib::wrap(cseperator);
+ seperator->show();
+ tool_item_group->add(*seperator);*/
+ //tool_palette.add(*seperator); //not the tool item group it probably should be the tool palette
+
+ //2-reg which is correct btw
+// seperator->set_draw(false);
+ Gtk::SeparatorToolItem *separator = Gtk::manage(new Gtk::SeparatorToolItem());
+ separator->show();
+ tool_item_group->insert(*separator);
+// tool_item_group->insert(*separator);
+
+ //Gtk::Separator *separator = Gtk::manage(new Gtk::Separator());
+ //separator->show();
+ //tool_item_group->add(*separator); //has to be a tool item
+
+ //another one
+ // tool_palette.append(*create_tool_separator());
+
+ //ok so basically we have to add this separator to the tool_item_group as palettes only take groups
+
+
+ Gtk::RadioButtonGroup interpolation_group;
+ //button1
+ Gtk::ToolButton *clamped_button = manage(new Gtk::ToolButton(
+ *manage(new Gtk::Image(
+ Gtk::StockID("synfig-interpolation_type_clamped"),
+ Gtk::IconSize::from_name("synfig-small_icon_16x16") )),
+ "_Clamped" ));
+ clamped_button->signal_clicked().connect( [this](){
+
+ current_widget_timetrack->set_interpolation(synfig::INTERPOLATION_CLAMPED);
+
+ } );
+ tool_item_group->add(*clamped_button);
+
+ //button2
+ Gtk::ToolButton *tcb_button = manage(new Gtk::ToolButton(
+ *manage(new Gtk::Image(
+ Gtk::StockID("synfig-interpolation_type_tcb"),
+ Gtk::IconSize::from_name("synfig-small_icon_16x16") )),
+ "_TCB" ));
+
+ tcb_button->signal_clicked().connect( [this](){
+
+ current_widget_timetrack->set_interpolation(synfig::INTERPOLATION_TCB);
+
+ } );
+
+ tool_item_group->add(*tcb_button);
+ //button3
+ Gtk::ToolButton *const_button = manage(new Gtk::ToolButton(
+ *manage(new Gtk::Image(
+ Gtk::StockID("synfig-interpolation_type_const"),
+ Gtk::IconSize::from_name("synfig-small_icon_16x16") )),
+ "_Constant" ));
+
+ const_button->signal_clicked().connect( [this](){
+
+ current_widget_timetrack->set_interpolation(synfig::INTERPOLATION_CONSTANT);
+
+ } );
+ tool_item_group->add(*const_button);
+
+ //button4
+ Gtk::ToolButton *ease_button = manage(new Gtk::ToolButton(
+ *manage(new Gtk::Image(
+ Gtk::StockID("synfig-interpolation_type_ease"),
+ Gtk::IconSize::from_name("synfig-small_icon_16x16") )),
+ "_Ease In/Out" ));
+ ease_button->signal_clicked().connect( [this](){
+
+ current_widget_timetrack->set_interpolation(synfig::INTERPOLATION_HALT);
+ } );
+ tool_item_group->add(*ease_button);
+
+ //button5
+ Gtk::ToolButton *linear_button = manage(new Gtk::ToolButton(
+ *manage(new Gtk::Image(
+ Gtk::StockID("synfig-interpolation_type_linear"),
+ Gtk::IconSize::from_name("synfig-small_icon_16x16") )),
+ "_Linear" ));
+ tool_item_group->add(*linear_button);
+ linear_button->signal_clicked().connect( [this](){
+
+ current_widget_timetrack->set_interpolation(synfig::INTERPOLATION_LINEAR);
+
+ } );
+
+ // Gtk::RadioToolButton::RadioToolButton(Gtk::RadioToolButton::Group&, const Gtk::StockID&)
+ tool_palette.add(*tool_item_group);
+ tool_palette.set_sensitive(true);
+}
+
+void Dock_Timetrack2::update_tool_palette_action()
+{
+ if (!current_widget_timetrack)
+ return;
+ Widget_Timetrack::ActionState action_state = current_widget_timetrack->get_action_state();
+ std::string action_state_name = Widget_Timetrack::get_action_state_name(action_state);
+
+ Gtk::RadioToolButton * button = action_button_map[action_state_name];
+ if (!button)
+ button = action_button_map[Widget_Timetrack::get_action_state_name(Widget_Timetrack::NONE)];
+ if (!button)
+ button = action_button_map[Widget_Timetrack::get_action_state_name(Widget_Timetrack::MOVE)];
+
+ if (button)
+ button->set_active(true);
+}
diff --git a/synfig-studio/src/gui/states/state_rotate.cpp b/synfig-studio/src/gui/states/state_rotate.cpp
index d55b4db9af6..1b428993dd1 100644
--- a/synfig-studio/src/gui/states/state_rotate.cpp
+++ b/synfig-studio/src/gui/states/state_rotate.cpp
@@ -43,6 +43,7 @@
#include
#include
#include
+#include
#include
#include
@@ -90,6 +91,7 @@ class DuckDrag_Rotate : public DuckDrag_Base
public:
CanvasView::Handle canvas_view_;
bool use_magnitude;
+ bool constrain;
DuckDrag_Rotate();
void begin_duck_drag(Duckmatic* duckmatic, const synfig::Vector& offset);
bool end_duck_drag(Duckmatic* duckmatic);
@@ -115,6 +117,15 @@ class studio::StateRotate_Context : public sigc::trackable
Gtk::CheckButton scale_checkbutton;
Gtk::Box scale_box;
+ Gtk::Label constrain_label;
+
+ bool shift_pressed;
+
+ void set_shift_pressed(bool value);
+
+ void set_constrain_flag(bool x) { if(duck_dragger_ && x!=duck_dragger_->constrain)
+ {duck_dragger_->constrain=x;} }
+
public:
bool get_scale_flag()const { return scale_checkbutton.get_active(); }
@@ -122,6 +133,8 @@ class studio::StateRotate_Context : public sigc::trackable
Smach::event_result event_stop_handler(const Smach::event& x);
Smach::event_result event_refresh_tool_options(const Smach::event& x);
+ Smach::event_result event_key_down_handler(const Smach::event& x);
+ Smach::event_result event_key_up_handler(const Smach::event& x);
void refresh_tool_options();
@@ -147,6 +160,9 @@ StateRotate::StateRotate():
{
insert(event_def(EVENT_REFRESH_TOOL_OPTIONS,&StateRotate_Context::event_refresh_tool_options));
insert(event_def(EVENT_STOP,&StateRotate_Context::event_stop_handler));
+ insert(event_def(EVENT_WORKAREA_KEY_DOWN,&StateRotate_Context::event_key_down_handler));
+ insert(event_def(EVENT_WORKAREA_KEY_UP,&StateRotate_Context::event_key_up_handler));
+
}
StateRotate::~StateRotate()
@@ -188,7 +204,8 @@ StateRotate_Context::StateRotate_Context(CanvasView* canvas_view):
canvas_view_(canvas_view),
is_working(*canvas_view),
settings(synfigapp::Main::get_selected_input_device()->settings()),
- duck_dragger_(new DuckDrag_Rotate())
+ duck_dragger_(new DuckDrag_Rotate()),
+ shift_pressed()
{
duck_dragger_->canvas_view_=get_canvas_view();
@@ -209,11 +226,17 @@ StateRotate_Context::StateRotate_Context(CanvasView* canvas_view):
scale_box.pack_start(scale_label, true, true, 0);
scale_box.pack_start(scale_checkbutton, false, false, 0);
+ constrain_label.set_label(_("Shift to constrain"));
+ constrain_label.set_halign(Gtk::ALIGN_START);
+ constrain_label.set_valign(Gtk::ALIGN_CENTER);
+
// Toolbox layout
options_grid.attach(title_label,
0, 0, 2, 1);
options_grid.attach(scale_box,
0, 1, 2, 1);
+ options_grid.attach(constrain_label,
+ 0, 2, 2, 1);
scale_checkbutton.signal_toggled().connect(sigc::mem_fun(*this,&StateRotate_Context::refresh_scale_flag));
@@ -253,6 +276,49 @@ StateRotate_Context::event_refresh_tool_options(const Smach::event& /*x*/)
return Smach::RESULT_ACCEPT;
}
+Smach::event_result
+StateRotate_Context::event_key_down_handler(const Smach::event &x)
+{
+ const EventKeyboard& event(*reinterpret_cast(&x));
+ switch(event.keyval)
+ {
+ case GDK_KEY_Shift_L:
+ case GDK_KEY_Shift_R:
+ set_shift_pressed(true);
+ break;
+ default:
+ set_shift_pressed(event.modifier&GDK_SHIFT_MASK);
+ break;
+ }
+ return Smach::RESULT_OK;
+
+}
+
+Smach::event_result
+StateRotate_Context::event_key_up_handler(const Smach::event &x)
+{
+ const EventKeyboard& event(*reinterpret_cast(&x));
+ switch(event.keyval)
+ {
+ case GDK_KEY_Shift_L:
+ case GDK_KEY_Shift_R:
+ set_shift_pressed(false);
+ break;
+ default:
+ break;
+ }
+ return Smach::RESULT_OK;
+
+}
+
+void StateRotate_Context::set_shift_pressed(bool value)
+{
+ if (shift_pressed == value)
+ return;
+ shift_pressed = value;
+ set_constrain_flag(shift_pressed);
+}
+
Smach::event_result
StateRotate_Context::event_stop_handler(const Smach::event& /*x*/)
{
@@ -282,7 +348,8 @@ DuckDrag_Rotate::DuckDrag_Rotate():
original_mag(),
bad_drag(),
move_only(),
- use_magnitude(true)
+ use_magnitude(true),
+ constrain()
{ }
void
@@ -343,6 +410,8 @@ DuckDrag_Rotate::duck_drag(Duckmatic* duckmatic, const synfig::Vector& vector)
return;
//std::set::iterator iter;
+ duckmatic->set_axis_lock(false);
+
synfig::Vector vect(duckmatic->snap_point_to_grid(vector)-center+snap);
const DuckList selected_ducks(duckmatic->get_selected_ducks());
@@ -376,6 +445,14 @@ DuckDrag_Rotate::duck_drag(Duckmatic* duckmatic, const synfig::Vector& vector)
Angle::tan angle(vect[1],vect[0]);
angle=original_angle-angle;
+
+ if (constrain){
+ Angle::deg angleDeg(static_cast(angle));
+ float degrees = angleDeg.get()/15;
+ angleDeg= Angle::deg(degrees>0?std::floor(degrees)*15:std::ceil(degrees)*15);
+ angle = Angle::tan(static_cast(angleDeg));
+ }
+
Real mag(vect.mag()/original_mag);
Real sine(Angle::sin(angle).get());
Real cosine(Angle::cos(angle).get());
diff --git a/synfig-studio/src/gui/workarea.h b/synfig-studio/src/gui/workarea.h
index c1cebfc66f5..781d3561076 100644
--- a/synfig-studio/src/gui/workarea.h
+++ b/synfig-studio/src/gui/workarea.h
@@ -246,6 +246,7 @@ class WorkArea : public Gtk::Grid, public Duckmatic
-- ** -- P U B L I C D A T A -----------------------------------------------
*/
+ bool ruler_status= true;
// used in renderer_ducks.cpp
bool solid_lines;
@@ -362,8 +363,9 @@ class WorkArea : public Gtk::Grid, public Duckmatic
void refresh_dimension_info();
- void set_show_rulers(bool visible);
-
+ void show_ruler();
+ void set_show_rulers(bool visible)
+
//! Enables showing of the grid
void enable_grid();
//! Disables showing of the grid