mail-notification

Fork of Jean-Yves Lefort's mail-notification, a tray icon to notify of new mail
git clone https://code.djc.id.au/git/mail-notification/

src/mn-non-linear-range.c (4011B) - raw

      1 /*
      2  * Mail Notification
      3  * Copyright (C) 2003-2008 Jean-Yves Lefort <jylefort@brutele.be>
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation; either version 3 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License along
     16  * with this program; if not, write to the Free Software Foundation, Inc.,
     17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     18  */
     19 
     20 #include <math.h>
     21 #include "mn-non-linear-range.h"
     22 #include "mn-util.h"
     23 
     24 typedef struct
     25 {
     26   const MNNonLinearRangeBlock	*blocks;
     27   int				num_blocks;
     28 } RangeInfo;
     29 
     30 static GQuark info_quark = 0;
     31 
     32 static void
     33 global_init (void)
     34 {
     35   if (! info_quark)
     36     info_quark = g_quark_from_static_string("mn-non-linear-range-info");
     37 }
     38 
     39 static RangeInfo *
     40 get_info (GtkRange *range)
     41 {
     42   RangeInfo *info;
     43 
     44   g_return_val_if_fail(GTK_IS_RANGE(range), NULL);
     45   g_return_val_if_fail(info_quark != 0, NULL);
     46 
     47   info = g_object_get_qdata(G_OBJECT(range), info_quark);
     48   g_return_val_if_fail(info != NULL, NULL);
     49 
     50   return info;
     51 }
     52 
     53 static int
     54 get_block_len (const MNNonLinearRangeBlock *block)
     55 {
     56   g_return_val_if_fail(block != NULL, -1);
     57 
     58   return ((block->max - block->min) / block->step) + 1;
     59 }
     60 
     61 void
     62 mn_non_linear_range_setup_static (GtkRange *range,
     63 				  const MNNonLinearRangeBlock *blocks,
     64 				  int num_blocks)
     65 {
     66   RangeInfo *info;
     67   int i;
     68   int num_values = 0;
     69 
     70   g_return_if_fail(GTK_IS_RANGE(range));
     71   g_return_if_fail(blocks != NULL);
     72   g_return_if_fail(num_blocks > 0);
     73 
     74   global_init();
     75 
     76   info = g_new0(RangeInfo, 1);
     77   info->blocks = blocks;
     78   info->num_blocks = num_blocks;
     79 
     80   g_object_set_qdata_full(G_OBJECT(range), info_quark, info, g_free);
     81 
     82   for (i = 0; i < num_blocks; i++)
     83     num_values += get_block_len(&blocks[i]);
     84 
     85   gtk_range_set_range(range, 0, num_values - 1);
     86 }
     87 
     88 gboolean
     89 mn_is_non_linear_range (gpointer object)
     90 {
     91   return object != NULL && info_quark != 0 && g_object_get_qdata(object, info_quark) != NULL;
     92 }
     93 
     94 int
     95 mn_non_linear_range_get_value (GtkRange *range)
     96 {
     97   RangeInfo *info;
     98   int raw;
     99   int offset = 0;
    100   int i;
    101 
    102   g_return_val_if_fail(GTK_IS_RANGE(range), -1);
    103 
    104   info = get_info(range);
    105 
    106   raw = (int) gtk_range_get_value(range);
    107 
    108   for (i = 0; i < info->num_blocks; i++)
    109     {
    110       const MNNonLinearRangeBlock *block = &info->blocks[i];
    111       int next_offset;
    112 
    113       next_offset = offset + get_block_len(block);
    114 
    115       if (raw >= offset && raw < next_offset)
    116 	return block->min + (raw - offset) * block->step;
    117 
    118       offset = next_offset;
    119     }
    120 
    121   g_assert_not_reached();
    122   return -1;
    123 }
    124 
    125 static int
    126 value_to_index (RangeInfo *info, int value)
    127 {
    128   int offset = 0;
    129   int i;
    130 
    131   /* if smaller than the first value, use the first value */
    132   if (value < info->blocks[0].min)
    133     return 0;
    134 
    135   for (i = 0; i < info->num_blocks; i++)
    136     {
    137       const MNNonLinearRangeBlock *block = &info->blocks[i];
    138 
    139       if (value >= block->min && value <= block->max)
    140 	{
    141 	  int rounded;
    142 	  int index;
    143 	  int j;
    144 
    145 	  /* round the value to the nearest step */
    146 	  rounded = lround((double) value / block->step) * block->step;
    147 
    148 	  for (j = block->min, index = 0; j <= block->max; j += block->step, index++)
    149 	    if (j == rounded)
    150 	      return offset + index;
    151 
    152 	  g_assert_not_reached();
    153 	}
    154 
    155       offset += get_block_len(block);
    156     }
    157 
    158   /* block not found: fallback to the maximum value */
    159   return offset - 1;
    160 }
    161 
    162 /*
    163  * If the value is not found in the blocks, the nearest existing value
    164  * will be used.
    165  */
    166 void
    167 mn_non_linear_range_set_value (GtkRange *range, int value)
    168 {
    169   g_return_if_fail(GTK_IS_RANGE(range));
    170 
    171   gtk_range_set_value(range, value_to_index(get_info(range), value));
    172 }