Commit de59173
add a scrollbar and some new scrolling code in OverView
Changed files (6)
modifiedsrc/GlyphRange.valamodifiedsrc/MainWindow.valamodifiedsrc/OverView.valaaddedsrc/Scrollbar.valamodifiedsrc/TestCases.valamodifiedsrc/wscript
Diff
@@ -77,7 +77,8 @@ class GlyphRange { } public void use_full_unicode_range () {- add_range ('\0', (unichar) 0xA868FE00);+ // add_range ('\0', (unichar) 0xA868FE00);+ add_range ('\0', (unichar) 0xFFF8); } // Todo: complete localized alphabetical sort åäö is the right order for example.@@ -22,7 +22,8 @@ namespace Supplement { public class MainWindow : Gtk.Window { - HBox hb; + HBox list_box; + HBox canvas_box; static TabBar tabs; VBox tab_box; @@ -36,6 +37,8 @@ public class MainWindow : Gtk.Window { static DrawingArea margin_bottom; static DrawingArea margin_right; + + static OverView over_view; public MainWindow (string title) { singleton = this; @@ -64,27 +67,31 @@ public class MainWindow : Gtk.Window { FontDisplay fd = tab.get_display (); glyph_canvas.set_current_glyph (fd); }); - - OverView over_view = new OverView(); - + + over_view = new OverView(); + tabs.add_unique_tab (content, 60, true); tabs.add_unique_tab (over_view, 75, false); - tabs.select_tab_name ("Content"); - - hb = new HBox (false, 0); + tabs.select_tab_name ("File"); + + canvas_box = new HBox (false, 0); + canvas_box.pack_start (glyph_canvas, true, true, 0); tab_box = new VBox (false, 0); tab_box.pack_start (tabs, false, false, 0); - tab_box.pack_start (glyph_canvas, true, true, 0); + + tab_box.pack_start (canvas_box, true, true, 0); + tab_box.pack_start (tool_tip, false, false, 0); tab_box.pack_start (margin_bottom, false, false, 0); - hb.pack_start (tab_box, true, true, 0); - hb.pack_start (tools, false, false, 0); - hb.pack_start (margin_right, false, false, 0); + list_box = new HBox (false, 0); + list_box.pack_start (tab_box, true, true, 0); + list_box.pack_start (tools, false, false, 0); + list_box.pack_start (margin_right, false, false, 0); - add (hb); + add (list_box); key_snooper_install (global_key_bindings, null); @@ -51,10 +51,16 @@ class OverView : FontDisplay { List<GlyphCollection> deleted_glyphs = new List<GlyphCollection> (); + Scrollbar scrollbar;+ public OverView (GlyphRange? range = null) {+ GlyphRange gr;+ if (range == null) {- glyph_range = new GlyphRange ();- glyph_range.use_default_range ();+ gr = new GlyphRange ();+ gr.use_default_range ();+ + set_glyph_range (gr); } reset_zoom ();@@ -83,6 +89,50 @@ class OverView : FontDisplay { z.store_current_view (); } });+ + scrollbar = new Scrollbar ();+ scrollbar.signal_scroll.connect ((delta, delta_last, absolute) => {+ int64 adjustement = (int64) (-delta_last * get_height ());+ int64 pixels = (int64) (-5.0 * delta_last * nail_height);+ + // print (@"(int64) $(-delta_last) * $(over_view.get_height ()) = $adjustement \n");+ print (@"$delta\n");+ + if (absolute <= 0.002) {+ first_character = 0;+ first_visible = 0;+ selected = 0;+ scroll_top ();+ } else if (absolute >= 1) {+ scroll_bottom ();+ } else {+ scroll_to (absolute);+ }+ +/*+ if (-0.1 < delta < 0.1) {+ scroll_adjustment (pixels);+ } else {+ scroll_to (absolute);+ }+*/ + + redraw_area (0, 0, allocation.width, allocation.height);+ });+ + update_scrollbar ();+ }+ + void scroll_bottom () {+ scroll_to_position (glyph_range.length () - items_per_row * (rows - 1));+ }+ + public double get_height () {+ return 2.0 * nail_height * (glyph_range.length () / rows);+ }++ public bool selected_char_is_visible () {+ return first_visible <= selected <= first_visible + items_per_row * rows; } public override void scroll_wheel_up (Gdk.EventScroll e) {@@ -258,8 +308,8 @@ class OverView : FontDisplay { character_string = glyph_range.get_char ((uint32) index); if (character_string == "") {- warning ("Got null character as name for glyph.");- break;+ warning (@"Got null character as name for glyph. Index: $index");+ // break; } cr.save ();@@ -359,7 +409,8 @@ class OverView : FontDisplay { double y; uint64 t; int i;-+ int n_items;+ while (visible_characters.length () > 9) { visible_characters.remove_link (visible_characters.first ()); }@@ -372,11 +423,12 @@ class OverView : FontDisplay { cr.fill (); cr.restore (); - int n_items = (allocation.width / nail_width);+ scrollbar.draw (cr, allocation);+ + n_items = (allocation.width / nail_width); rows = (allocation.height / nail_height);- - if (items_per_row != n_items) {- + + if (items_per_row != n_items) { if (items_per_row == 0) { items_per_row = n_items; first_visible = first_character;@@ -384,20 +436,14 @@ class OverView : FontDisplay { items_per_row = n_items; first_visible = first_character; - while (selected <= first_visible)+ while (selected < first_visible) { scroll (-nail_height);+ } - while (selected <= first_visible + rows * n_items)- scroll (nail_height);- + while (selected < first_visible + rows * n_items) {+ scroll (nail_height); + } }- - scroll_top ();- - while (first_visible < selected) {- scroll_rows (1);- }- scroll_rows (-2); } width = nail_width * items_per_row;@@ -435,22 +481,80 @@ class OverView : FontDisplay { } } - public void scroll (int pixel_adjustment) {- view_offset_y += pixel_adjustment;+ public void scroll_adjustment (double pixel_adjustment) {+ if (first_visible <= 0) {+ return;+ }++ if (first_visible + rows * items_per_row >= glyph_range.length ()) {+ return;+ } - if (view_offset_y >= 0) { - view_offset_y = -nail_height;- first_visible -= items_per_row;+ scroll ((int64) pixel_adjustment);+ }+ + void default_position () {+ scroll_top ();+ scroll_rows (1);+ }+ + void scroll_to_position (int64 r) {+ // bottom+ if (r > glyph_range.length () - items_per_row * rows) {+ return; } - if (view_offset_y < -nail_height) {- view_offset_y = 0;- first_visible += items_per_row;+ if (r < 0) {+ scroll_top ();+ return; } - if (first_visible < 0) {+ default_position ();+ + // DEL:+ // view_offset_y = 0;+ // first_character = (uint32) r;+ first_visible = r;+ selected = (uint32) r;+ + adjust_scroll ();+ }+ + public void scroll_to (double percent) {+ int64 r;+ + print (@"percent $percent\n");+ + r = (int64) (percent * glyph_range.length () / rows);+ r *= items_per_row;+ + scroll_to_position (r);+ + print (@"i: $r $(glyph_range.get_char ((uint32) r)) l: $(glyph_range.length ()) \n");+ }+ + private void scroll (int64 pixel_adjustment) {++ if (first_visible < 0 && pixel_adjustment < 0) { scroll_top ();+ return; }+ + view_offset_y += pixel_adjustment;+ + if (view_offset_y >= 0) {+ while (view_offset_y > nail_height) { + view_offset_y -= nail_height;+ first_visible -= items_per_row;+ }++ first_visible -= items_per_row;+ view_offset_y -= nail_height;+ } else if (view_offset_y < -nail_height) {+ view_offset_y = 0;+ first_visible += items_per_row;+ }+ } public void scroll_top () {@@ -482,7 +586,9 @@ class OverView : FontDisplay { } } - private void key_down () {+ public void key_down () {+ update_scrollbar ();+ if (glyph_range.length () == 0) return; if (at_bottom ()) {@@ -513,10 +619,14 @@ class OverView : FontDisplay { adjust_scroll (); } - private void key_up () {+ public void key_up () {+ update_scrollbar ();+ if (glyph_range.length () == 0) return; - warn_if_fail (selected >= first_character);+ if (selected < first_character) { + warn_if_reached ();+ } if (selected < first_character + items_per_row) { scroll_top ();@@ -689,9 +799,15 @@ class OverView : FontDisplay { } public override void motion_notify (EventMotion e) {+ if (e.x > allocation.x - 10) {+ scrollbar.motion_notify (e);+ } } - public override void button_release (EventButton event) {+ public override void button_release (EventButton e) {+ if (e.x > allocation.x - 10) {+ scrollbar.button_release (e);+ } } public override void leave_notify (EventCrossing e) {@@ -771,7 +887,11 @@ class OverView : FontDisplay { } public override void button_press (EventButton e) {- selection_click (e);+ if (e.x > allocation.width - 10) {+ scrollbar.button_press (e);+ } else {+ selection_click (e);+ } } /** Returns true if overview shows the last character. */@@ -783,7 +903,7 @@ class OverView : FontDisplay { string c = glyph_range.get_char (selected); bool done = false; uint32 i;- uint32 len;+ uint32 len = 0; glyph_range = range; @@ -849,10 +969,15 @@ class OverView : FontDisplay { scroll_top (); } }- ++ update_scrollbar (); redraw_area (0, 0, allocation.width, allocation.height); } + public void update_scrollbar () {+ scrollbar.set_handle_size (items_per_row * rows / (double) glyph_range.get_length ());+ scrollbar.set_handle_position (first_visible / (double) glyph_range.get_length ());+ } } }new file mode 100644@@ -0,0 +1,181 @@+/*+ Copyright (C) 2012 Johan Mattsson++ 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 Cairo;+using Gdk;+using Gtk;++namespace Supplement {++class Scrollbar : DrawingArea {+ Allocation alloc;++ double pos = 0;+ double height = 0.1;+ + double y = 0;+ double h = 0;+ + double y_begin = 0;+ double y_last = 0;+ bool move = false;+ bool visible = true;++ public signal void signal_scroll (double delta, double delta_last, double absolute);++ public Scrollbar () {+ add_events (EventMask.BUTTON_PRESS_MASK | EventMask.BUTTON_RELEASE_MASK | EventMask.POINTER_MOTION_MASK);+ + expose_event.connect ((t, e)=> {+ Context cr = cairo_create (get_window ());+ + get_allocation (out alloc);+ allocation = alloc;+ + draw (cr, alloc);+ + return true;+ });+ + button_press_event.connect ((t, e)=> {+ button_press (e); + return true;+ });++ button_release_event.connect ((t, e)=> {+ button_release (e);+ return true;+ });+ + motion_notify_event.connect ((t, e)=> {+ motion_notify (e); + return true;+ });+ }+ + public void set_handle_size (double s) {+ height = (s < 0.01) ? 0.01 : s;+ print (@"height $height\n");+ + if (height > 1) {+ height = 1;+ }+ + h = height * alloc.height;+ }++ public void set_handle_position (double p) {+ print (@"p: $p\n");+ pos = (p > 0) ? p : 0;+ y = pos * alloc.height;+ }+ + public void button_press (EventButton e) {+ move = true;+ y_begin = e.y;+ y_last = e.y;+ + print ("press\n");+ }+ + public void button_release (EventButton event) {+ move = false;+ }+ + public double get_height () {+ return alloc.height;+ }+ + public void motion_notify (EventMotion e) {+ print (@"notify $move \n");+ double d = 0;+ double dl = 0;+ double m;+ + h = height * alloc.height;+ m = alloc.height;+ + if (move && 0 < e.y < m) {+ d = e.y - y_begin;+ dl = e.y - y_last;+ y += dl;+ y_last = e.y;+ }++ if (y < 0) {+ y = 0;+ }++ if (y > alloc.height - h) {+ y = alloc.height - h;+ d = 0;+ dl = 0;+ }+ + if (move) {+ pos = y / alloc.height;+ }+ + print (@"pos $pos\n");+ + if (move) {+ signal_scroll (d / (m - h), dl / (m -h), y / (m - h));+ pos = y / m;+ }++ }+ + public void draw (Context cr, Allocation alloc) {+ double ax, ay, aw, ah;++ this.alloc = alloc;++ ax = alloc.width - 10;+ ay = 0;+ aw = alloc.width;+ ah = alloc.height;+ + if (!visible) {+ cr.save ();+ cr.rectangle (ax, ay, aw, ah);+ cr.set_line_width (0);+ cr.set_source_rgba (194/255.0, 194/255.0, 194/255.0, 1);+ cr.fill_preserve ();+ cr.stroke ();+ cr.restore ();+ return;+ }+ + cr.save ();+ cr.rectangle (ax, ay, aw, ah);+ cr.set_line_width (0);+ cr.set_source_rgba (183/255.0, 200/255.0, 223/255.0, 1);+ cr.fill_preserve ();+ cr.stroke ();+ cr.restore (); + + cr.save ();+ cr.rectangle (ax, pos * alloc.height, alloc.width, ah * height);+ cr.set_line_width (0);+ cr.set_source_rgba (133/255.0, 143/255.0, 174/255.0, 1);+ cr.fill_preserve ();+ cr.stroke ();+ cr.restore (); + }+}++}@@ -23,6 +23,7 @@ class TestCases { public List<Test> test_cases; public TestCases () {+ add (test_overview, "Overview"); add (test_data_reader, "Font data reader"); add (test_argument, "Argument list"); add (test_glyph_ranges, "Glyph ranges");@@ -38,6 +39,40 @@ class TestCases { add (test_save_backup, "Save backup"); } + public static void test_overview () {+ OverView o = MainWindow.get_overview ();++ warn_if_fail (o.selected_char_is_visible ());+ + for (int i = 0; i < 10; i++) {+ o.key_down ();+ warn_if_fail (o.selected_char_is_visible ());+ }++ for (int i = 0; i < 15; i++) {+ o.key_up ();+ warn_if_fail (o.selected_char_is_visible ());+ }++ for (int i = 0; i < 6; i++) {+ o.key_down ();+ warn_if_fail (o.selected_char_is_visible ());+ }++ for (int i = 0; i < 3; i++) {+ o.key_down ();+ warn_if_fail (o.selected_char_is_visible ());+ }+ + for (int i = 0; i < 2000; i++) {+ o.scroll_adjustment (5);+ }++ for (int i = 0; i < 2000; i++) {+ o.scroll_adjustment (-5);+ }+ }+ public static void test_data_reader () { FontData fd = new FontData (); @@ -36,10 +36,11 @@ SUPPLEMENT_MAIN = [ 'Path.vala', 'PenTool.vala', 'ResizeTool.vala', - 'Supplement.vala', 'SaveDialog.vala', + 'Scrollbar.vala', 'ShrinkTool.vala', 'SpinButton.vala', + 'Supplement.vala', 'Svg.vala', 'SvgFontFormatWriter.vala', 'Preferences.vala',