Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
R
randomizer
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Francois Techene
randomizer
Commits
5178daf1
Commit
5178daf1
authored
Jan 13, 2021
by
Francois Techene
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implementing fade animations + some refactoring
parent
121edcdf
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
624 additions
and
60 deletions
+624
-60
src/main.c
src/main.c
+12
-1
src/meson.build
src/meson.build
+1
-0
src/randomizer-animation.c
src/randomizer-animation.c
+328
-0
src/randomizer-animation.h
src/randomizer-animation.h
+58
-0
src/randomizer-window.c
src/randomizer-window.c
+161
-26
src/randomizer-window.ui
src/randomizer-window.ui
+60
-33
src/randomizer.gresource.xml
src/randomizer.gresource.xml
+1
-0
src/style.css
src/style.css
+3
-0
No files found.
src/main.c
View file @
5178daf1
...
...
@@ -26,7 +26,18 @@ static void
on_startup
(
GtkApplication
*
app
)
{
//g_print ("Init Libhandy\n");
hdy_init
();
//
GtkCssProvider
*
css_provider
=
gtk_css_provider_new
();
hdy_init
();
gtk_css_provider_load_from_resource
(
css_provider
,
"/sm/puri/Randomizer/style.css"
);
gtk_style_context_add_provider_for_screen
(
gdk_screen_get_default
(),
GTK_STYLE_PROVIDER
(
css_provider
),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION
);
g_object_unref
(
css_provider
);
}
static
void
...
...
src/meson.build
View file @
5178daf1
randomizer_sources = [
'main.c',
'randomizer-animation.c',
'randomizer-window.c',
]
...
...
src/randomizer-animation.c
0 → 100644
View file @
5178daf1
/* Copyright YEAR Copyright Holder
*
* Licence text goes here
*
* Author: you <your@email>
*/
#include "randomizer-animation.h"
#include <math.h>
struct
_RandomizerAnimation
{
GInitiallyUnowned
parent_instance
;
/* Instance variables */
animated_widget_property
animated_property
;
animation_curve_type
curve_type
;
GtkWidget
*
widget
;
gint64
start_time
;
/* ms */
gint64
end_time
;
/* ms */
gint64
duration
;
/* ms */
guint
tick_cb_id
;
guint
animation_id
;
gdouble
value_from
;
gdouble
value_to
;
RandomizerAnimationCompleteCallback
on_complete_cb
;
gpointer
user_data
;
gboolean
can_animate
;
gboolean
is_running
;
};
G_DEFINE_TYPE
(
RandomizerAnimation
,
randomizer_animation
,
G_TYPE_INITIALLY_UNOWNED
)
/***********************************************************
* Static functions
*
*/
static
gboolean
is_widget_animatable
(
GtkWidget
*
widget
)
{
gboolean
enable_animations
=
TRUE
;
g_assert
(
GTK_IS_WIDGET
(
widget
));
g_object_get
(
gtk_widget_get_settings
(
widget
),
"gtk-enable-animations"
,
&
enable_animations
,
NULL
);
return
enable_animations
;
}
static
gdouble
get_value_for_current_time
(
RandomizerAnimation
*
self
,
gdouble
current_time
)
{
gdouble
value
;
gdouble
t
;
gdouble
low_value
;
gdouble
high_value
;
gboolean
decrease
=
(
self
->
value_from
>
self
->
value_to
);
if
(
decrease
)
{
low_value
=
self
->
value_to
;
high_value
=
self
->
value_from
;
}
else
{
low_value
=
self
->
value_from
;
high_value
=
self
->
value_to
;
}
// Logic from http://gizma.com/easing/#cub2
//
switch
(
self
->
curve_type
)
{
case
LINEAR_ANIMATION
:
t
=
current_time
/
self
->
duration
;
value
=
low_value
*
(
1
.
0
-
t
)
+
high_value
*
t
;
break
;
case
EASE_IN_ANIMATION
:
t
=
current_time
/
self
->
duration
;
value
=
high_value
*
t
*
t
*
t
+
low_value
;
break
;
case
EASE_OUT_ANIMATION
:
t
=
(
current_time
/
self
->
duration
)
-
1
;
value
=
high_value
*
(
t
*
t
*
t
+
1
)
+
low_value
;
break
;
case
EASE_IN_AND_OUT_ANIMATION
:
t
=
current_time
/
(
self
->
duration
/
2
)
;
if
(
t
<
1
)
{
value
=
high_value
/
2
*
t
*
t
*
t
+
low_value
;
}
else
{
t
-=
2
;
value
=
high_value
/
2
*
(
t
*
t
*
t
+
2
)
+
low_value
;
}
break
;
}
if
(
decrease
)
{
value
=
self
->
value_from
-
value
;
}
return
value
;
}
static
gdouble
get_animation_value
(
RandomizerAnimation
*
self
,
GdkFrameClock
*
frame_clock
)
{
gint64
frame_time
;
gdouble
current_time
;
frame_time
=
gdk_frame_clock_get_frame_time
(
frame_clock
)
/
1000
;
frame_time
=
MIN
(
frame_time
,
self
->
end_time
);
current_time
=
frame_time
-
self
->
start_time
;
return
get_value_for_current_time
(
self
,
current_time
);
}
static
void
set_animation_value
(
RandomizerAnimation
*
self
,
gdouble
value
)
{
switch
(
self
->
animated_property
)
{
case
OPACITY_ANIMATED_PROPERTY
:
gtk_widget_set_opacity
(
self
->
widget
,
value
);
break
;
case
SIZE_ANIMATED_PROPERTY
:
// TODO : Implement size animation
break
;
case
X_TRANSLATION_ANIMATED_PROPERTY
:
// TODO : Implement translation animation
break
;
case
Y_TRANSLATION_ANIMATED_PROPERTY
:
// TODO : Implement translation animation
break
;
default
:
g_print
(
"There is no animation implemented for this property
\n
"
);
}
}
static
gboolean
update_animation
(
GtkWidget
*
widget
,
GdkFrameClock
*
frame_clock
,
RandomizerAnimation
*
self
)
{
gboolean
should_continue
=
TRUE
;
gint64
frame_time
;
gdouble
value
;
frame_time
=
gdk_frame_clock_get_frame_time
(
frame_clock
)
/
1000
;
if
(
frame_time
>=
self
->
end_time
)
{
value
=
self
->
value_to
;
should_continue
=
FALSE
;
}
else
{
value
=
get_animation_value
(
self
,
frame_clock
);
}
//g_print("Value : %f\n", value);
set_animation_value
(
self
,
value
);
return
should_continue
;
}
static
void
on_update_animation_complete_cb
(
RandomizerAnimation
*
self
)
{
randomizer_animation_stop
(
self
);
}
/***********************************************************
* Public functions
*
*/
void
randomizer_animation_start
(
RandomizerAnimation
*
self
,
animation_curve_type
curve_type
,
gdouble
value_from
,
gdouble
value_to
,
gint64
duration
,
RandomizerAnimationCompleteCallback
on_complete_cb
,
gpointer
user_data
)
{
g_return_if_fail
(
self
!=
NULL
);
self
->
curve_type
=
curve_type
;
self
->
value_from
=
value_from
;
self
->
value_to
=
value_to
;
self
->
duration
=
duration
;
self
->
on_complete_cb
=
on_complete_cb
;
self
->
user_data
=
user_data
;
self
->
can_animate
=
TRUE
;
// If there cannot be an animation,
// complete the animation.
//
if
(
!
is_widget_animatable
(
self
->
widget
)
||
!
gtk_widget_get_mapped
(
self
->
widget
)
||
self
->
duration
<=
0
)
{
self
->
can_animate
=
FALSE
;
self
->
animation_id
=
0
;
set_animation_value
(
self
,
self
->
value_to
);
randomizer_animation_stop
(
self
);
return
;
}
GdkFrameClock
*
frame_clock
;
gint64
frame_time
;
frame_clock
=
gtk_widget_get_frame_clock
(
self
->
widget
);
frame_time
=
gdk_frame_clock_get_frame_time
(
frame_clock
);
self
->
start_time
=
frame_time
/
1000
;
self
->
end_time
=
self
->
start_time
+
self
->
duration
;
// Don't register a new animation callback if one is already running.
//
if
(
!
self
->
is_running
)
{
self
->
tick_cb_id
=
gtk_widget_add_tick_callback
(
self
->
widget
,
update_animation
,
self
,
on_update_animation_complete_cb
);
self
->
animation_id
=
self
->
tick_cb_id
;
}
self
->
is_running
=
TRUE
;
}
void
randomizer_animation_stop
(
RandomizerAnimation
*
self
)
{
g_return_if_fail
(
self
!=
NULL
);
self
->
is_running
=
FALSE
;
if
(
self
->
tick_cb_id
!=
0
)
{
gtk_widget_remove_tick_callback
(
self
->
widget
,
self
->
tick_cb_id
);
self
->
tick_cb_id
=
0
;
}
self
->
start_time
=
0
;
self
->
end_time
=
0
;
if
(
self
->
on_complete_cb
!=
NULL
)
{
self
->
on_complete_cb
(
self
,
self
->
user_data
);
}
}
guint
randomizer_animation_get_id
(
RandomizerAnimation
*
self
)
{
return
self
->
animation_id
;
}
/***********************************************************
* Init
*
*/
static
void
randomizer_animation_init
(
RandomizerAnimation
*
self
)
{
// initialisation goes here
self
->
tick_cb_id
=
0
;
self
->
animation_id
=
0
;
self
->
start_time
=
0
;
self
->
end_time
=
0
;
}
static
void
randomizer_animation_class_init
(
RandomizerAnimationClass
*
class
)
{
// virtual function overrides go here
// property and signal definitions go here
}
RandomizerAnimation
*
randomizer_animation_new
(
GtkWidget
*
widget
,
animated_widget_property
property
)
{
g_return_val_if_fail
(
GTK_IS_WIDGET
(
widget
),
NULL
);
RandomizerAnimation
*
self
;
self
=
g_object_new
(
RANDOMIZER_TYPE_ANIMATION
,
NULL
);
self
->
widget
=
widget
;
self
->
animated_property
=
property
;
return
self
;
}
src/randomizer-animation.h
0 → 100644
View file @
5178daf1
/* Copyright YEAR Copyright Holder
*
* Licence text goes here
*
* Author: you <your@email>
*/
#ifndef _my_app_window_h_
#define _my_app_window_h_
#include <gtk/gtk.h>
/*
* Animation types
*/
typedef
enum
{
NO_ANIMATED_PROPERTY
,
OPACITY_ANIMATED_PROPERTY
,
SIZE_ANIMATED_PROPERTY
,
X_TRANSLATION_ANIMATED_PROPERTY
,
Y_TRANSLATION_ANIMATED_PROPERTY
}
animated_widget_property
;
typedef
enum
{
LINEAR_ANIMATION
,
EASE_IN_ANIMATION
,
EASE_OUT_ANIMATION
,
EASE_IN_AND_OUT_ANIMATION
}
animation_curve_type
;
G_BEGIN_DECLS
#define RANDOMIZER_TYPE_ANIMATION (randomizer_animation_get_type ())
G_DECLARE_FINAL_TYPE
(
RandomizerAnimation
,
randomizer_animation
,
RANDOMIZER
,
ANIMATION
,
GInitiallyUnowned
)
typedef
void
(
*
RandomizerAnimationCompleteCallback
)
(
RandomizerAnimation
*
self
,
gpointer
user_data
);
RandomizerAnimation
*
randomizer_animation_new
(
GtkWidget
*
widget
,
animated_widget_property
property
);
void
randomizer_animation_start
(
RandomizerAnimation
*
self
,
animation_curve_type
curve_type
,
gdouble
start_value
,
gdouble
end_value
,
gint64
duration
,
RandomizerAnimationCompleteCallback
on_complete_cb
,
gpointer
user_data
);
void
randomizer_animation_stop
(
RandomizerAnimation
*
self
);
guint
randomizer_animation_get_id
(
RandomizerAnimation
*
self
);
G_END_DECLS
#endif
/* _my_app_window_h_ */
src/randomizer-window.c
View file @
5178daf1
...
...
@@ -18,6 +18,7 @@
#include "randomizer-config.h"
#include "randomizer-window.h"
#include "randomizer-animation.h"
#include <sys/time.h>
struct
_RandomizerWindow
...
...
@@ -25,21 +26,27 @@ struct _RandomizerWindow
HdyWindow
parent_instance
;
/* Template widgets */
GtkStack
*
stack
;
HdyViewSwitcherTitle
*
switcher_title
;
Gtk
Label
*
boolean_label
;
Gtk
Image
*
dice_image
;
Gtk
Spinner
*
yes_no_spinner
;
Gtk
Label
*
answer_label
;
GtkImage
*
dice_image_1
;
GtkImage
*
dice_image_2
;
RandomizerAnimation
*
fade_answer_animation
;
gboolean
answer_is_displayed
;
};
G_DEFINE_TYPE
(
RandomizerWindow
,
randomizer_window
,
HDY_TYPE_WINDOW
)
/***********************************************************
* Randomize function
* Randomize function
s
*
*/
static
int
get_randomized_number_with_range
(
int
lower
,
int
upper
)
...
...
@@ -52,46 +59,126 @@ get_randomized_number_with_range (int lower,
return
num
;
}
/***********************************************************
* Yes / NO Answer tab
*
*/
static
void
randomize_
dice_image
(
GtkImage
*
dice_image
)
randomize_
answer
(
GtkLabel
*
label
)
{
int
num
=
get_randomized_number_with_range
(
1
,
6
);
char
arr
[
6
][
30
]
=
{
"Yes"
,
"No"
,
"Definitely"
,
"Don't count on it."
,
"Only you can find out."
,
"Maybe"
};
char
image_name
[
6
];
sprintf
(
image_name
,
"dice-%d"
,
num
);
int
num
=
get_randomized_number_with_range
(
0
,
5
);
gtk_label_set_text
(
label
,
arr
[
num
]);
gtk_image_set_from_icon_name
(
dice_image
,
image_name
,
GTK_ICON_SIZE_INVALID
);
}
static
void
hide_answer_cb
(
RandomizerAnimation
*
animation
,
RandomizerWindow
*
self
)
{
gtk_label_set_text
(
self
->
answer_label
,
"Yes or No?"
);
randomizer_animation_start
(
self
->
fade_answer_animation
,
EASE_IN_ANIMATION
,
0
,
1
,
500
,
NULL
,
self
);
}
static
gboolean
hide_answer
(
RandomizerWindow
*
self
)
{
if
(
self
->
answer_is_displayed
)
{
randomizer_animation_start
(
self
->
fade_answer_animation
,
EASE_IN_ANIMATION
,
1
,
0
,
2000
,
hide_answer_cb
,
self
);
self
->
answer_is_displayed
=
FALSE
;
}
return
FALSE
;
}
static
void
on_update_answer_animation_complete_cb
(
RandomizerAnimation
*
animation
,
RandomizerWindow
*
self
)
{
g_timeout_add
(
5000
,
G_SOURCE_FUNC
(
hide_answer
),
self
);
}
static
void
answer_randomize_clicked_cb
(
GtkButton
*
btn
,
RandomizerWindow
*
self
)
{
randomize_answer
(
self
->
answer_label
);
randomizer_animation_start
(
self
->
fade_answer_animation
,
LINEAR_ANIMATION
,
0
,
1
,
1000
,
on_update_answer_animation_complete_cb
,
self
);
self
->
answer_is_displayed
=
TRUE
;
}
/***********************************************************
*
Callbacks
*
Dices tab
*
*/
static
void
boolean_randomize_clicked_cb
(
GtkButton
*
btn
,
RandomizerWindow
*
self
)
set_dice_image_with_value
(
GtkImage
*
dice_image
,
int
value
)
{
int
num
=
get_randomized_number_with_range
(
0
,
1
);
char
image_name
[
6
];
sprintf
(
image_name
,
"dice-%d"
,
value
);
if
(
num
==
0
)
{
gtk_label_set_text
(
self
->
boolean_label
,
"No"
);
}
else
{
gtk_label_set_text
(
self
->
boolean_label
,
"Yes"
);
}
gtk_image_set_from_icon_name
(
dice_image
,
image_name
,
GTK_ICON_SIZE_INVALID
);
}
static
void
dice_randomize_clicked_cb
(
GtkButton
*
btn
,
randomize_dice_image
(
GtkImage
*
dice_image
)
{
set_dice_image_with_value
(
dice_image
,
get_randomized_number_with_range
(
1
,
6
));
}
static
void
dice_randomize_clicked_cb
(
GtkButton
*
btn
,
RandomizerWindow
*
self
)
{
randomize_dice_image
(
self
->
dice_image
);
randomize_dice_image
(
self
->
dice_image
_1
);
randomize_dice_image
(
self
->
dice_image_2
);
}
...
...
@@ -110,6 +197,42 @@ dice_number_changed_cb (GtkSpinButton *spinbutton,
}
}
/***********************************************************
* Init Tabs
*
*/
static
void
init_answer_tab
(
RandomizerWindow
*
self
)
{
gtk_widget_set_opacity
(
GTK_WIDGET
(
self
->
answer_label
),
1
);
}
static
void
init_dice_tab
(
RandomizerWindow
*
self
)
{
set_dice_image_with_value
(
self
->
dice_image_1
,
1
);
set_dice_image_with_value
(
self
->
dice_image_2
,
1
);
}
static
void
switched_tab_cb
(
GtkStack
*
current_stack
,
RandomizerWindow
*
self
)
{
const
char
*
page_name
=
gtk_stack_get_visible_child_name
(
current_stack
);
g_print
(
"on new tab : %s
\n
"
,
page_name
);
if
(
strcmp
(
page_name
,
"dice"
)
==
0
)
{
//init_dice_tab(self);
}
else
{
//init_answer_tab(self);
}
}
/***********************************************************
* Init
*
...
...
@@ -121,13 +244,17 @@ randomizer_window_class_init (RandomizerWindowClass *klass)
GtkWidgetClass
*
widget_class
=
GTK_WIDGET_CLASS
(
klass
);
gtk_widget_class_set_template_from_resource
(
widget_class
,
"/sm/puri/Randomizer/randomizer-window.ui"
);
gtk_widget_class_bind_template_child
(
widget_class
,
RandomizerWindow
,
stack
);
gtk_widget_class_bind_template_child
(
widget_class
,
RandomizerWindow
,
switcher_title
);
gtk_widget_class_bind_template_child
(
widget_class
,
RandomizerWindow
,
boolean_label
);
gtk_widget_class_bind_template_child
(
widget_class
,
RandomizerWindow
,
dice_image
);
gtk_widget_class_bind_template_child
(
widget_class
,
RandomizerWindow
,
yes_no_spinner
);
gtk_widget_class_bind_template_child
(
widget_class
,
RandomizerWindow
,
answer_label
);
gtk_widget_class_bind_template_child
(
widget_class
,
RandomizerWindow
,
dice_image_1
);
gtk_widget_class_bind_template_child
(
widget_class
,
RandomizerWindow
,
dice_image_2
);
gtk_widget_class_bind_template_callback
(
widget_class
,
boolean
_randomize_clicked_cb
);
gtk_widget_class_bind_template_callback
(
widget_class
,
answer
_randomize_clicked_cb
);
gtk_widget_class_bind_template_callback
(
widget_class
,
dice_randomize_clicked_cb
);
gtk_widget_class_bind_template_callback
(
widget_class
,
dice_number_changed_cb
);
gtk_widget_class_bind_template_callback
(
widget_class
,
switched_tab_cb
);
}
static
void
...
...
@@ -135,7 +262,15 @@ randomizer_window_init (RandomizerWindow *self)
{
gtk_widget_init_template
(
GTK_WIDGET
(
self
));
/* Init UI */
self
->
fade_answer_animation
=
randomizer_animation_new
(
GTK_WIDGET
(
self
->
answer_label
),
OPACITY_ANIMATED_PROPERTY
);
init_answer_tab
(
self
);
gtk_widget_hide
(
GTK_WIDGET
(
self
->
dice_image_2
)
);
}
RandomizerWindow
*
...
...
src/randomizer-window.ui
View file @
5178daf1
...
...
@@ -31,6 +31,7 @@
<object
class=
"GtkStack"
id=
"stack"
>
<property
name=
"visible"
>
True
</property>
<property
name=
"can_focus"
>
False
</property>
<signal
name=
"notify::visible-child"
handler=
"switched_tab_cb"
swapped=
"no"
/>
<child>
<object
class=
"GtkBox"
>
<property
name=
"visible"
>
True
</property>
...
...
@@ -41,49 +42,75 @@
<property
name=
"vexpand"
>
True
</property>
<property
name=
"hexpand"
>
True
</property>
<property
name=
"spacing"
>
24
</property>
<child>
<object
class=
"GtkLabel"
id=
"boolean_label"
>
<property
name=
"visible"
>
True
</property>
<property
name=
"can_focus"
>
False
</property>
<property
name=
"label"
translatable=
"yes"
></property>
<property
name=
"justify"
>
center
</property>
<property
name=
"wrap"
>
True
</property>
<property
name=
"opacity"
>
1
</property>
<attributes>
<attribute
name=
"weight"
value=
"bold"
/>
<attribute
name=
"scale"
value=
"2"
/>
</attributes>
</object>
</child>
<child>
<object
class=
"GtkLabel"
id=
"boolean_description_label"
>
<object
class=
"GtkBox"
>
<property
name=
"visible"
>
True
</property>
<property
name=
"orientation"
>
vertical
</property>
<property
name=
"can_focus"
>
False
</property>
<property
name=
"label"
translatable=
"yes"
>
Yes or No ?
</property>
<property
name=
"justify"
>
center
</property>
<property
name=
"wrap"
>
True
</property>
<property
name=
"opacity"
>
0.5
</property>
<attributes>
<attribute
name=
"weight"
value=
"normal"
/>
<attribute
name=
"scale"
value=
"1"
/>
</attributes>
<property
name=
"halign"
>
center
</property>
<property
name=
"valign"
>
center
</property>
<property
name=
"vexpand"
>
True
</property>
<property
name=
"hexpand"
>
True
</property>
<property
name=
"spacing"
>
24
</property>
<child>
<object
class=
"GtkSpinner"
id=
"yes_no_spinner"
>
<property
name=
"visible"
>
True
</property>
<property
name=
"can_focus"
>
False
</property>
</object>
</child>
<child>
<object
class=
"GtkLabel"
id=
"answer_label"
>
<property
name=
"visible"
>
True
</property>
<property
name=
"can_focus"
>
False
</property>
<property
name=
"label"
translatable=
"yes"
>
Yes or No ?
</property>
<property
name=
"justify"
>
center
</property>