[gnome-characters] characterList: Rewrite as a single drawing area



commit 919d5c9647bbb7624e2032dc7b7b3cba22a8403c
Author: Daiki Ueno <dueno src gnome org>
Date:   Tue Feb 10 17:34:47 2015 +0900

    characterList: Rewrite as a single drawing area
    
    We used to implement it as a list box containing several drawing area.
    To make reflow implementation simpler, this consolidate all the
    rendering logic into a single place.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=740260

 data/org.gnome.Characters.gschema.xml |    2 +-
 src/characterList.js                  |  210 +++++++++++++--------------------
 2 files changed, 83 insertions(+), 129 deletions(-)
---
diff --git a/data/org.gnome.Characters.gschema.xml b/data/org.gnome.Characters.gschema.xml
index 1b28f16..ccf6b9d 100644
--- a/data/org.gnome.Characters.gschema.xml
+++ b/data/org.gnome.Characters.gschema.xml
@@ -1,7 +1,7 @@
 <schemalist gettext-domain="org.gnome.Characters">
   <schema id="org.gnome.Characters" path="/org/gnome/Characters/">
     <key name="font" type="s">
-      <default>'Cantarell'</default>
+      <default>'Cantarell 100'</default>
       <summary>Font to display characters</summary>
       <description>
        Use the font to render characters on the character list.
diff --git a/src/characterList.js b/src/characterList.js
index eb0a9d2..88fe5ac 100644
--- a/src/characterList.js
+++ b/src/characterList.js
@@ -1,6 +1,6 @@
 // -*- Mode: js; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*-
 //
-// Copyright (C) 2014  Daiki Ueno <dueno src gnome org>
+// Copyright (C) 2014-2015  Daiki Ueno <dueno src gnome org>
 //
 // This program is free software; you can redistribute it and/or
 // modify it under the terms of the GNU General Public License
@@ -30,97 +30,51 @@ const Main = imports.main;
 const Util = imports.util;
 
 const BASELINE_OFFSET = 0.85;
-const CELL_SIZE = 0.20;
 const CELLS_PER_ROW = 5;
-const CELL_PIXEL_SIZE = 100;
+const CELL_SIZE = 100;
 
-const CharacterListRowWidget = new Lang.Class({
-    Name: 'CharacterListRowWidget',
-    Extends: Gtk.DrawingArea,
-    Signals: {
-        'character-selected': { param_types: [ GObject.TYPE_STRING ] }
-    },
+function getCellSize(fontDescription) {
+    if (fontDescription == null
+        || fontDescription.get_size() == 0)
+        return CELL_SIZE;
+    return fontDescription.get_size() * 2 / Pango.SCALE;
+}
+
+const CharacterListRow = new Lang.Class({
+    Name: 'CharacterListRow',
+    Extends: GObject.Object,
 
     _init: function(params) {
         let filtered = Params.filter(params, { characters: null,
-                                               font: null,
-                                               cellWidth: null });
+                                               fontDescription: null });
         params = Params.fill(params, {});
         this.parent(params);
         this._characters = filtered.characters;
-        this._font = filtered.font;
-        this._cellWidth = filtered.cellWidth;
-        this.add_events(Gdk.EventMask.BUTTON_PRESS_MASK);
-        this.get_style_context().add_class('character-list-row');
-    },
-
-    vfunc_get_preferred_height: function() {
-        let [minWidth, natWidth] = this.vfunc_get_preferred_width();
-        return this.vfunc_get_preferred_height_for_width(minWidth);
-    },
-
-    vfunc_get_preferred_height_for_width: function(width) {
-        let rowHeight = width * CELL_SIZE;
-        return [rowHeight, rowHeight];
-    },
-
-    vfunc_get_preferred_width: function() {
-        return this.vfunc_get_preferred_width_for_height(0);
-    },
-
-    vfunc_get_preferred_width_for_height: function(height) {
-        let rowWidth = CELL_PIXEL_SIZE * CELLS_PER_ROW;
-        return [rowWidth, rowWidth];
-    },
-
-    vfunc_size_allocate: function(allocation) {
-        this.parent(allocation);
-
-        if (this._cellWidth < 0)
-            this._cellWidth = allocation.width * CELL_SIZE;
+        this._fontDescription = filtered.fontDescription;
     },
 
-    vfunc_button_press_event: function(event) {
-        let allocation = this.get_allocation();
-        let cellIndex = Math.floor(event.x / this._cellWidth);
-        if (cellIndex < this._characters.length)
-            this.emit('character-selected', this._characters[cellIndex]);
-    },
-
-    vfunc_draw: function(cr) {
-        // Use device coordinates directly, since PangoCairo doesn't
-        // work well with scaled matrix:
-        // https://bugzilla.gnome.org/show_bug.cgi?id=700592
-        let allocation = this.get_allocation();
-
-        // Clear the canvas.
-        // FIXME: Pick the background color from CSS.
-        cr.setSourceRGBA(1, 1, 1, 1);
-        cr.paint();
-        cr.setSourceRGBA(0, 0, 0, 1);
-
+    draw: function(cr, x, y, width, height) {
         let layout = PangoCairo.create_layout(cr);
-        let description = Pango.FontDescription.from_string(this._font);
-        description.set_absolute_size(this._cellWidth / 2 * Pango.SCALE);
-        layout.set_font_description(description);
+        layout.set_font_description(this._fontDescription);
 
         // Draw baseline.
         // FIXME: Pick the baseline color from CSS.
         cr.setSourceRGBA(114.0 / 255.0, 159.0 / 255.0, 207.0 / 255.0, 1.0);
         cr.setLineWidth(0.5);
-        cr.moveTo(0, BASELINE_OFFSET * allocation.height);
-        cr.relLineTo(allocation.width, 0);
+        cr.moveTo(x, y + BASELINE_OFFSET * height);
+        cr.relLineTo(width, 0);
         cr.stroke();
         cr.setSourceRGBA(0.0, 0.0, 0.0, 1.0);
 
         // Draw characters.  Do centering and attach to the baseline.
+        let cellSize = getCellSize(this._fontDescription);
         for (let i in this._characters) {
             layout.set_text(this._characters[i], -1);
             let layoutBaseline = layout.get_baseline() / Pango.SCALE;
             let [logicalRect, inkRect] = layout.get_extents();
-            cr.moveTo(this._cellWidth * i - logicalRect.x / Pango.SCALE +
-                      (this._cellWidth - logicalRect.width / Pango.SCALE) / 2,
-                      BASELINE_OFFSET * allocation.height - layoutBaseline);
+            cr.moveTo(x + cellSize * i - logicalRect.x / Pango.SCALE +
+                      (cellSize - logicalRect.width / Pango.SCALE) / 2,
+                      y + BASELINE_OFFSET * height - layoutBaseline);
             PangoCairo.show_layout(cr, layout);
         }
     },
@@ -128,7 +82,7 @@ const CharacterListRowWidget = new Lang.Class({
 
 const CharacterListWidget = new Lang.Class({
     Name: 'CharacterListWidget',
-    Extends: Gtk.Box,
+    Extends: Gtk.DrawingArea,
     Signals: {
         'character-selected': { param_types: [ GObject.TYPE_STRING ] }
     },
@@ -136,7 +90,7 @@ const CharacterListWidget = new Lang.Class({
         'font': GObject.ParamSpec.string(
             'font', '', '',
             GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE,
-            'Cantarell')
+            'Cantarell 100')
     },
 
     get font() {
@@ -144,10 +98,19 @@ const CharacterListWidget = new Lang.Class({
     },
 
     set font(v) {
-        if (v == this._font)
+        let fontDescription = Pango.FontDescription.from_string(v);
+        if (fontDescription.get_size() == 0)
+            fontDescription.set_size(CELL_SIZE);
+
+        fontDescription.set_absolute_size(
+            fontDescription.get_size() / 2 * Pango.SCALE);
+
+        if (this._fontDescription &&
+            fontDescription.equal(this._fontDescription))
             return;
 
         this._font = v;
+        this._fontDescription = fontDescription;
         if (this._characters) {
             this.setCharacters(this._characters);
             this.show_all();
@@ -155,13 +118,25 @@ const CharacterListWidget = new Lang.Class({
     },
 
     _init: function(params) {
-        params = Params.fill(params, { orientation: Gtk.Orientation.VERTICAL,
-                                       homogeneous: true });
+        params = Params.fill(params, {});
         this.parent(params);
         this.get_style_context().add_class('character-list');
-        Main.settings.bind('font', this, 'font', Gio.SettingsBindFlags.DEFAULT);
-        this._cellWidth = -1;
         this._cellsPerRow = CELLS_PER_ROW;
+        this._font = null;
+        this._fontDescription = null;
+        this._rows = [];
+        Main.settings.bind('font', this, 'font', Gio.SettingsBindFlags.DEFAULT);
+        this.add_events(Gdk.EventMask.BUTTON_PRESS_MASK);
+    },
+
+    vfunc_button_press_event: function(event) {
+        let allocation = this.get_allocation();
+        let cellSize = getCellSize(this._fontDescription);
+        let x = Math.floor(event.x / cellSize);
+        let y = Math.floor(event.y / cellSize);
+        let index = y * this._cellsPerRow + x;
+        if (index < this._characters.length)
+            this.emit('character-selected', this._characters[index]);
     },
 
     vfunc_get_preferred_height: function() {
@@ -170,13 +145,7 @@ const CharacterListWidget = new Lang.Class({
     },
 
     vfunc_get_preferred_height_for_width: function(width) {
-        let height = 0;
-        let children = this.get_children();
-        for (let index in children) {
-            let [minHeight, natHeight] =
-                children[index].get_preferred_height_for_width(width);
-            height += minHeight;
-        }
+        let height = this._rows.length * getCellSize(this._fontDescription);
         return [height, height];
     },
 
@@ -185,66 +154,32 @@ const CharacterListWidget = new Lang.Class({
     },
 
     vfunc_get_preferred_width_for_height: function(height) {
-        let width = 0;
-        let children = this.get_children();
-        if (children.length == 0)
-            width = CELL_PIXEL_SIZE * CELLS_PER_ROW;
-        else {
-            for (let index in children) {
-                let [minWidth, natWidth] =
-                    children[index].get_preferred_width_for_height(height);
-                width = Math.max(width, minWidth);
-            }
-        }
+        let width = this._cellsPerRow * getCellSize(this._fontDescription);
         return [width, width];
     },
 
     vfunc_size_allocate: function(allocation) {
         this.parent(allocation);
 
-        if (this._cellWidth < 0)
-            this._cellWidth = allocation.width * CELL_SIZE;
-
-        // Reflow if the number of cells per row has changed.
-        let cellsPerRow = Math.floor(allocation.width / this._cellWidth);
+        let cellSize = getCellSize(this._fontDescription);
+        let cellsPerRow = Math.floor(allocation.width / cellSize);
         if (cellsPerRow != this._cellsPerRow) {
+            // Reflow if the number of cells per row has changed.
             this._cellsPerRow = cellsPerRow;
             this.setCharacters(this._characters);
-            this.show_all();
-        }
-
-        // Make each row have the same height.
-        let rowHeight = this._cellWidth;
-        let children = this.get_children();
-        for (let index in children) {
-            let child = children[index];
-            var childAllocation = child.get_allocation();
-            childAllocation.x = allocation.x;
-            childAllocation.y = allocation.y + rowHeight * index;
-            childAllocation.width = allocation.width;
-            childAllocation.height = rowHeight;
-            child.size_allocate(childAllocation);
         }
     },
 
     _createCharacterListRow: function(characters) {
-        let rowWidget = new CharacterListRowWidget({
+        let row = new CharacterListRow({
             characters: characters,
-            font: this._font,
-            cellWidth: this._cellWidth
+            fontDescription: this._fontDescription
         });
-        rowWidget.connect('character-selected',
-                          Lang.bind(this, function(row, uc) {
-                              this.emit('character-selected', uc);
-                          }));
-        return rowWidget;
+        return row;
     },
 
     setCharacters: function(characters) {
-        let children = this.get_children();
-        for (let index in children)
-            this.remove(children[index]);
-
+        this._rows = [];
         this._characters = characters;
 
         if (characters.length == 0)
@@ -254,15 +189,34 @@ const CharacterListWidget = new Lang.Class({
         for (; stop <= characters.length; stop++) {
             if (stop % this._cellsPerRow == 0) {
                 let rowCharacters = characters.slice(start, stop);
-                let rowWidget = this._createCharacterListRow(rowCharacters);
-                this.pack_start(rowWidget, true, true, 0);
+                let row = this._createCharacterListRow(rowCharacters);
+                this._rows.push(row);
                 start = stop;
             }
         }
         if (start != stop - 1) {
             let rowCharacters = characters.slice(start, stop);
-            let rowWidget = this._createCharacterListRow(rowCharacters);
-            this.pack_start(rowWidget, true, true, 0);
+            let row = this._createCharacterListRow(rowCharacters);
+            this._rows.push(row);
         }
     },
+
+    vfunc_draw: function(cr) {
+        // Clear the canvas.
+        // FIXME: Pick the background color from CSS.
+        cr.setSourceRGBA(1, 1, 1, 1);
+        cr.paint();
+        cr.setSourceRGBA(0, 0, 0, 1);
+
+        // Use device coordinates directly, since PangoCairo doesn't
+        // work well with scaled matrix:
+        // https://bugzilla.gnome.org/show_bug.cgi?id=700592
+        let allocation = this.get_allocation();
+
+        let cellSize = getCellSize(this._fontDescription);
+        for (let index in this._rows) {
+            this._rows[index].draw(cr, 0, index * cellSize,
+                                   allocation.width, cellSize);
+        }
+    }
 });


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]