loading_indicator.vala 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /********************************************************************
  2. # Copyright 2014 Daniel 'grindhold' Brendle
  3. #
  4. # This file is part of Rainbow Lollipop.
  5. #
  6. # Rainbow Lollipop is free software: you can redistribute it and/or
  7. # modify it under the terms of the GNU General Public License
  8. # as published by the Free Software Foundation, either
  9. # version 3 of the License, or (at your option) any later
  10. # version.
  11. #
  12. # Rainbow Lollipop is distributed in the hope that it will be
  13. # useful, but WITHOUT ANY WARRANTY; without even the implied
  14. # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. # PURPOSE. See the GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public
  18. # License along with Rainbow Lollipop.
  19. # If not, see http://www.gnu.org/licenses/.
  20. *********************************************************************/
  21. using Math;
  22. namespace RainbowLollipop {
  23. /**
  24. * Represents a loading bar on top of the screen
  25. */
  26. class LoadingIndicator : Clutter.Actor {
  27. private LoadingIndicatorSlider slider;
  28. private bool loading;
  29. public LoadingIndicator(Clutter.Actor stage) {
  30. this.x = 0;
  31. this.y = 0;
  32. this.height = 3;
  33. this.opacity = 0x00;
  34. this.width = stage.width;
  35. this.background_color = Clutter.Color.from_string(Config.c.colorscheme.tracklist);
  36. this.add_constraint(
  37. new Clutter.BindConstraint(stage, Clutter.BindCoordinate.WIDTH, 0)
  38. );
  39. this.slider = new LoadingIndicatorSlider(this);
  40. this.slider.reactive = true;
  41. this.slider.transitions_completed.connect(this.do_transitions_completed);
  42. this.add_child(this.slider);
  43. }
  44. public void start() {
  45. this.loading = true;
  46. this.opacity = 0xFF;
  47. this.slider.do_animation_step();
  48. }
  49. public void stop() {
  50. this.loading = false;
  51. }
  52. public void do_transitions_completed() {
  53. if (!loading) {
  54. if (this.opacity != 0x00) {
  55. this.save_easing_state();
  56. this.opacity = 0x00;
  57. this.restore_easing_state();
  58. }
  59. } else {
  60. this.slider.do_animation_step();
  61. }
  62. }
  63. }
  64. /**
  65. * Represents the moving portion of the loading bar
  66. */
  67. class LoadingIndicatorSlider : Clutter.Actor {
  68. /**
  69. * Enumerates the states the animation of the
  70. * slider can be in
  71. */
  72. private enum AnimState {
  73. EXPANDING_RIGHT,
  74. CONTRACTING_RIGHT,
  75. EXPANDING_LEFT,
  76. CONTRACTING_LEFT
  77. }
  78. private AnimState anim_state = AnimState.EXPANDING_RIGHT;
  79. private const int SLIDER_WIDTH = 200;
  80. private Clutter.Canvas c;
  81. /**
  82. * Constructs a new loading indicator slider
  83. */
  84. public LoadingIndicatorSlider(LoadingIndicator parent) {
  85. this.c = new Clutter.Canvas();
  86. this.x = 0;
  87. this.y = 0;
  88. this.set_size(SLIDER_WIDTH,(int)roundf(parent.height));
  89. this.c.set_size(SLIDER_WIDTH,(int)roundf(parent.height));
  90. this.content = c;
  91. this.c.draw.connect(do_draw);
  92. this.c.invalidate();
  93. }
  94. /**
  95. * Draws the slider as a linear gradient with colors depending on
  96. * The currently selected colorscheme
  97. */
  98. public bool do_draw(Cairo.Context cr, int w, int h) {
  99. double stops = (double)Config.c.colorscheme.tracks.size;
  100. cr.set_source_rgba(0,0,0,0);
  101. cr.set_operator(Cairo.Operator.SOURCE);
  102. cr.paint();
  103. cr.set_operator(Cairo.Operator.OVER);
  104. var grad = new Cairo.Pattern.linear(0,0,w,0);
  105. grad.add_color_stop_rgba(0.0, 0, 0, 0, 0);
  106. int count = 1;
  107. double step = 1.0d/(stops+2);
  108. foreach (string cs in Config.c.colorscheme.tracks) {
  109. var c = Clutter.Color.from_string(cs);
  110. grad.add_color_stop_rgba(count*step,
  111. col_h2f(c.red),
  112. col_h2f(c.green),
  113. col_h2f(c.blue),
  114. 1.0);
  115. count++;
  116. }
  117. grad.add_color_stop_rgba(1.0, 0, 0, 0, 0);
  118. cr.set_source(grad);
  119. cr.rectangle(0,0,w,h);
  120. cr.fill();
  121. return true;
  122. }
  123. /**
  124. * Cycles through the animation steps and causes
  125. * clutter do do the according animation for the next step
  126. */
  127. public void do_animation_step() {
  128. this.save_easing_state();
  129. this.set_easing_duration(800);
  130. this.set_easing_mode(Clutter.AnimationMode.EASE_IN_OUT_QUART);
  131. switch(this.anim_state) {
  132. case AnimState.EXPANDING_RIGHT:
  133. this.width = this.get_parent().width;
  134. this.anim_state = AnimState.CONTRACTING_RIGHT;
  135. break;
  136. case AnimState.CONTRACTING_RIGHT:
  137. this.width = LoadingIndicatorSlider.SLIDER_WIDTH;
  138. this.x = this.get_parent().width - LoadingIndicatorSlider.SLIDER_WIDTH;
  139. this.anim_state = AnimState.EXPANDING_LEFT;
  140. break;
  141. case AnimState.EXPANDING_LEFT:
  142. this.width = this.get_parent().width;
  143. this.x = 0;
  144. this.anim_state = AnimState.CONTRACTING_LEFT;
  145. break;
  146. case AnimState.CONTRACTING_LEFT:
  147. this.width = LoadingIndicatorSlider.SLIDER_WIDTH;
  148. this.anim_state = AnimState.EXPANDING_RIGHT;
  149. break;
  150. }
  151. this.restore_easing_state();
  152. }
  153. }
  154. }