diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 5a42c79..e1dec5d 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,7 +1,7 @@ + package="com.forfolias.leleDroid" android:versionCode="4" + android:versionName="1.4"> @@ -10,7 +10,7 @@ - + > @@ -24,7 +24,9 @@ - + + - - - - - - + + + - - + - - - - - - + + - - - - - + + + + + + + \ No newline at end of file diff --git a/res/layout/chart_tooltip.xml b/res/layout/chart_tooltip.xml new file mode 100644 index 0000000..431ce5f --- /dev/null +++ b/res/layout/chart_tooltip.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + diff --git a/res/layout/dialog_color_picker.xml b/res/layout/dialog_color_picker.xml new file mode 100644 index 0000000..c96178a --- /dev/null +++ b/res/layout/dialog_color_picker.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/widget.xml b/res/layout/widget.xml index 692259a..031e98c 100644 --- a/res/layout/widget.xml +++ b/res/layout/widget.xml @@ -1,7 +1,10 @@ - + - + android:layout_marginLeft="10dp" android:layout_width="90dp" + android:src="@drawable/icon" android:clickable="true"> + android:layout_marginLeft="10dp" android:layout_height="wrap_content"> + \ No newline at end of file diff --git a/res/layout/widget_conf.xml b/res/layout/widget_conf.xml index 007a7c1..7c662d1 100644 --- a/res/layout/widget_conf.xml +++ b/res/layout/widget_conf.xml @@ -1,25 +1,122 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + \ No newline at end of file diff --git a/res/values-en/strings.xml b/res/values-en/strings.xml index 3567693..c8c80e4 100644 --- a/res/values-en/strings.xml +++ b/res/values-en/strings.xml @@ -5,13 +5,13 @@ Information Soldier Add soldier - leleDroid Widget Configuration - Select soldier : + Select soldier - Delete - View + Details + Pie chart Edit - + Delete + End date Start date Name @@ -20,8 +20,7 @@ Days served Remaining days - - Soldier details + Soldier details Seconds... Minutes... Hours... @@ -38,8 +37,21 @@ Cancel Back + leleDroid Widget Configuration + Text color + Display soldiers\' military rank + Display soldiers\' name + Display soldiers\' military rank image + Display soldiers\' rest service days + Display percentage progress bar There is no available soldier. Please add a soldier at the leleDroid application + Select at least one component to display + + Select on click action + None + + Please fill in the days off Please fill in the name of the soldier Please fill in the extra days diff --git a/res/values/dimen.xml b/res/values/dimen.xml new file mode 100644 index 0000000..2069420 --- /dev/null +++ b/res/values/dimen.xml @@ -0,0 +1,5 @@ + + + 1dp + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 305c123..a149cfa 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -5,12 +5,12 @@ Πληροφορίες Στρατιώτης Προσθήκη στρατιώτη - Ρυθμίσεις του leleDroid widget - Επιλογή στρατιώτη : + Επιλογή στρατιώτη - Διαγραφή - Προβολή + Λεπτομέρειες + Γράφημα Επεξεργασία + Διαγραφή Ημερομηνία απόλυσης Ημερομηνία κατάταξης @@ -20,8 +20,7 @@ Ημέρες που υπηρετήθηκαν Ημέρες που απομένουν - - Λεπτομέρειες στρατιώτη + Λεπτομέρειες στρατιώτη Δευτερόλεπτα... Λεπτά... Ώρες... @@ -37,8 +36,19 @@ Άκυρο Επιστροφή + Ρυθμίσεις του leleDroid widget + Χρώμα κειμένου + Εμφάνιση λελεδοβαθμού + Εμφάνιση ονόματος + Εμφάνιση εικόνας λελεδοβαθμού + Εμφάνιση εναπομείναντων ημερών + Εμφάνιση μπάρας ποσοστού Δεν υπάρχει κάποιος διαθέσιμος στρατιώτης. Παρακαλώ προσθέστε κάποιον από την εφαρμογή leleDroid + Επιλέξτε τουλάχιστον ένα στοιχείο για εμφάνιση + Ενέργεια κατά το κλικ + Καμία + Παρακαλώ συμπληρώστε της ημέρες άδειας Παρακαλώ συμπληρώστε το όνομα στρατιώτη Παρακαλώ συμπληρώστε τις ημέρες φυλακής diff --git a/res/xml/colorpicker.xml b/res/xml/colorpicker.xml new file mode 100644 index 0000000..193cc7a --- /dev/null +++ b/res/xml/colorpicker.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/res/xml/widget.xml b/res/xml/widget.xml index 9b0fa56..c52deef 100644 --- a/res/xml/widget.xml +++ b/res/xml/widget.xml @@ -1,6 +1,5 @@ + android:configure="com.forfolias.leleDroid.StrWidgetConfig" android:minHeight="100dp" android:minWidth="100dp"> diff --git a/src/com/forfolias/leleDroid/ChartView.java b/src/com/forfolias/leleDroid/ChartView.java new file mode 100644 index 0000000..daa68f7 --- /dev/null +++ b/src/com/forfolias/leleDroid/ChartView.java @@ -0,0 +1,103 @@ +package com.forfolias.leleDroid; + +import org.achartengine.ChartFactory; +import org.achartengine.GraphicalView; +import org.achartengine.model.CategorySeries; +import org.achartengine.renderer.DefaultRenderer; +import org.achartengine.renderer.SimpleSeriesRenderer; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Color; +import android.os.Bundle; +import android.view.Window; +import android.widget.LinearLayout; +import android.widget.TextView; + +public class ChartView extends Activity { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + requestWindowFeature(Window.FEATURE_NO_TITLE); + + setContentView(R.layout.chart); + Integer id = -1; + + Intent intent = getIntent(); + Bundle extras = intent.getExtras(); + if (extras != null) { + id = extras.getInt("id", -1); + } + + if (id <= 0) { + finish(); + } else { + Str str = Str.getStrFromId(id); + makeChart(str.getName(), str.getAdeia(), str.getRestDays(), str.getPastDays()); + } + } + + protected void makeChart(String name, Integer adeia, Integer ipiretisimoYpoloipo, + Integer perasan) { + + if (adeia >= ipiretisimoYpoloipo) { + adeia = ipiretisimoYpoloipo; + ipiretisimoYpoloipo = 0; + } else { + ipiretisimoYpoloipo -= adeia; + } + + if (perasan < 0) { + perasan = 0; + } + + if (ipiretisimoYpoloipo < 0) { + ipiretisimoYpoloipo = 0; + adeia = 0; + } + if (adeia < 0) { + adeia = 0; + } + + if (ipiretisimoYpoloipo == 0 && adeia == 0 && perasan == 0) { + perasan = 1; + } + + String[] labels = { adeia.toString(), ipiretisimoYpoloipo.toString(), + perasan.toString() }; + GraphicalView mChartView; + LinearLayout layout = (LinearLayout) findViewById(R.id.pieChartActivity); + TextView nameTv = (TextView) findViewById(R.id.ChartTvName); + nameTv.setText(name); + + double[] values = new double[] { adeia, ipiretisimoYpoloipo, perasan }; + int[] colors = new int[] { Color.BLUE, Color.RED, Color.GREEN }; + DefaultRenderer renderer = buildCategoryRenderer(colors); + mChartView = ChartFactory.getPieChartView(this, + buildCategoryDataset("Γράφημα", labels, values), renderer); + + layout.addView(mChartView); + } + + protected DefaultRenderer buildCategoryRenderer(int[] colors) { + DefaultRenderer renderer = new DefaultRenderer(); + for (int color : colors) { + SimpleSeriesRenderer r = new SimpleSeriesRenderer(); + r.setColor(color); + renderer.addSeriesRenderer(r); + } + renderer.setLabelsTextSize(10); + renderer.setShowLegend(false); + return renderer; + } + + protected CategorySeries buildCategoryDataset(String title, + String[] labels, double[] values) { + CategorySeries series = new CategorySeries(title); + series.add(labels[0], values[0]); + series.add(labels[1], values[1]); + series.add(labels[2], values[2]); + return series; + } +} diff --git a/src/com/forfolias/leleDroid/ColorPickerDialog.java b/src/com/forfolias/leleDroid/ColorPickerDialog.java new file mode 100644 index 0000000..2aceb96 --- /dev/null +++ b/src/com/forfolias/leleDroid/ColorPickerDialog.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2010 Daniel Nilsson + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.forfolias.leleDroid; + +import com.forfolias.leleDroid.views.ColorPanelView; +import com.forfolias.leleDroid.views.ColorPickerView; +import com.forfolias.leleDroid.views.ColorPickerView.OnColorChangedListener; +import android.app.AlertDialog; +import android.content.Context; +import android.graphics.PixelFormat; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; + +public class ColorPickerDialog extends AlertDialog implements + ColorPickerView.OnColorChangedListener { + + private ColorPickerView mColorPicker; + + private ColorPanelView mOldColor; + private ColorPanelView mNewColor; + + private OnColorChangedListener mListener; + + protected ColorPickerDialog(Context context, int initialColor) { + super(context); + + init(initialColor); + } + + private void init(int color) { + // To fight color branding. + getWindow().setFormat(PixelFormat.RGBA_8888); + + setUp(color); + + } + + private void setUp(int color) { + LayoutInflater inflater = (LayoutInflater) getContext() + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View layout = inflater.inflate(R.layout.dialog_color_picker, null); + + setView(layout); + + setTitle("Pick a Color"); + // setIcon(android.R.drawable.ic_dialog_info); + + mColorPicker = (ColorPickerView) layout + .findViewById(R.id.color_picker_view); + mOldColor = (ColorPanelView) layout.findViewById(R.id.old_color_panel); + mNewColor = (ColorPanelView) layout.findViewById(R.id.new_color_panel); + + ((LinearLayout) mOldColor.getParent()).setPadding(Math + .round(mColorPicker.getDrawingOffset()), 0, Math + .round(mColorPicker.getDrawingOffset()), 0); + + mColorPicker.setOnColorChangedListener(this); + + mOldColor.setColor(color); + mColorPicker.setColor(color, true); + + } + + public void onColorChanged(int color) { + + mNewColor.setColor(color); + + if (mListener != null) { + mListener.onColorChanged(color); + } + + } + + public void setAlphaSliderVisible(boolean visible) { + mColorPicker.setAlphaSliderVisible(visible); + } + + public int getColor() { + return mColorPicker.getColor(); + } + +} diff --git a/src/com/forfolias/leleDroid/Details.java b/src/com/forfolias/leleDroid/Details.java index b119b0b..b22ffc0 100644 --- a/src/com/forfolias/leleDroid/Details.java +++ b/src/com/forfolias/leleDroid/Details.java @@ -127,7 +127,11 @@ public void setChart(Integer adeia, Integer ipiretisimoYpoloipo, if (adeia < 0) { adeia = 0; } - + + if (ipiretisimoYpoloipo == 0 && adeia == 0 && perasan == 0) { + perasan = 1; + } + String[] labels = { adeia.toString(), ipiretisimoYpoloipo.toString(), perasan.toString() }; GraphicalView mChartView; @@ -143,7 +147,7 @@ public void setChart(Integer adeia, Integer ipiretisimoYpoloipo, layout.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { LayoutInflater inflater = getLayoutInflater(); - View layout = inflater.inflate(R.layout.chart, + View layout = inflater.inflate(R.layout.chart_tooltip, (ViewGroup) findViewById(R.id.LL1)); Toast toastView = new Toast(getBaseContext()); diff --git a/src/com/forfolias/leleDroid/Properties.java b/src/com/forfolias/leleDroid/Properties.java index f89a3a7..1fbc1dd 100644 --- a/src/com/forfolias/leleDroid/Properties.java +++ b/src/com/forfolias/leleDroid/Properties.java @@ -4,7 +4,6 @@ import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; - import android.app.Activity; import android.app.DatePickerDialog; import android.app.DatePickerDialog.OnDateSetListener; @@ -26,7 +25,6 @@ public class Properties extends Activity { private EditText activeDateDisplay; private Calendar activeDate; - int id; @Override @@ -191,8 +189,7 @@ public boolean checkFilak() { public boolean checkDates(String dateIn, String dateOut) { Toast toast = null; - String myFormatString = "dd/MM/yyyy"; - SimpleDateFormat df = new SimpleDateFormat(myFormatString); + SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy"); Date date1 = null; Date date2 = null; diff --git a/src/com/forfolias/leleDroid/Str.java b/src/com/forfolias/leleDroid/Str.java index e0bac1c..db52d88 100644 --- a/src/com/forfolias/leleDroid/Str.java +++ b/src/com/forfolias/leleDroid/Str.java @@ -168,6 +168,7 @@ public Float getPososto(){ } public static Str getStrFromId(Integer num) { + String line = "0 * 0 * 0/0/0 * 0/0/0 * 0 * 0"; Integer c = 0; Str strat = new Str(); @@ -184,6 +185,7 @@ public static Str getStrFromId(Integer num) { return strat; } strat.setStrFromString(line); + return strat; } @@ -204,21 +206,12 @@ public static String getStrFromIdToString(Integer num) { return line; } - public static List getStrList() { + public static List getStrList() { List list = new ArrayList(); - Str item = new Str(); - String line = "0 * 0 * 0/0/0 * 0/0/0 * 0 * 0"; - - try { - BufferedReader in = new BufferedReader(new FileReader(dataFile)); - while ((line = in.readLine()) != null) { - item.setStrFromString(line); - list.add(item); - item = new Str(); - } - in.close(); - } catch (IOException e) { - Log.e(TAG, "getStrList error : " + e.getLocalizedMessage()); + Integer N = getLengh(); + + for (int i = 0 ; i < N ; i++){ + list.add(getStrFromId(i+1)); } return list; } @@ -366,7 +359,7 @@ public static Integer getLengh() { try { is = new BufferedInputStream(new FileInputStream(dataFile)); } catch (FileNotFoundException e) { - Log.e(TAG, "getLengh error A : " + e.getLocalizedMessage()); + Log.e(TAG, "getLengh error. FileNotFound : " + e.getLocalizedMessage()); return 0; } try { diff --git a/src/com/forfolias/leleDroid/StrWidget.java b/src/com/forfolias/leleDroid/StrWidget.java index 80df359..0e54c35 100644 --- a/src/com/forfolias/leleDroid/StrWidget.java +++ b/src/com/forfolias/leleDroid/StrWidget.java @@ -1,8 +1,11 @@ package com.forfolias.leleDroid; +import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.Context; +import android.content.Intent; +import android.view.View; import android.widget.RemoteViews; public class StrWidget extends AppWidgetProvider { @@ -10,30 +13,87 @@ public class StrWidget extends AppWidgetProvider { @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { - + final int N = appWidgetIds.length; for (int i = 0; i < N; i++) { + int appWidgetId = appWidgetIds[i]; - String id = StrWidgetConfig.getStrId(context, appWidgetId); - updateAppWidget(context, appWidgetManager, appWidgetId, id); + String id = StrWidgetConfig.getPref(context, appWidgetId, "id_"); + String act = StrWidgetConfig.getPref(context, appWidgetId, + "action_"); + String TextColor = StrWidgetConfig.getPref(context, appWidgetId, + "textColor_"); + String Vathm = StrWidgetConfig.getPref(context, appWidgetId, + "displayVathmos_"); + String Name = StrWidgetConfig.getPref(context, appWidgetId, + "displayName_"); + String Image = StrWidgetConfig.getPref(context, appWidgetId, + "displayImage_"); + String Days = StrWidgetConfig.getPref(context, appWidgetId, + "displayDays_"); + String Prog = StrWidgetConfig.getPref(context, appWidgetId, + "displayProg_"); + + if (Integer.parseInt(id) <= 0) + return; + + updateAppWidget(context, appWidgetManager, appWidgetId, + Integer.parseInt(id), Integer.parseInt(act), TextColor, + Vathm, Name, Image, Days, Prog); } } static void updateAppWidget(Context context, - AppWidgetManager appWidgetManager, int appWidgetId, String id) { + AppWidgetManager appWidgetManager, int appWidgetId, Integer id, + Integer act, String tC, String V, String Nam, String Image, + String Days, String Prog) { RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget); - Str theOne = Str.getStrFromId(Integer.parseInt(id)); + Str theOne = Str.getStrFromId(id); String vathmos = theOne.getVathmo(); String onoma = theOne.getName(); String meres = theOne.getRestDays().toString(); + views.setTextColor(R.id.strVathmos, Integer.parseInt(tC)); + views.setTextColor(R.id.strName, Integer.parseInt(tC)); + views.setTextColor(R.id.strMeres, Integer.parseInt(tC)); + views.setTextViewText(R.id.strVathmos, vathmos); views.setTextViewText(R.id.strName, onoma); - views.setTextViewText(R.id.strMeres, meres + " " + context.getString(R.string.plusToday)); + views.setTextViewText(R.id.strMeres, + meres + " " + context.getString(R.string.plusToday)); views.setImageViewResource(R.id.strImg, theOne.getImg()); + views.setProgressBar(R.id.strProg, 100, theOne.getPososto().intValue(), + false); + + if (V == "0") + views.setViewVisibility(R.id.strVathmos, View.GONE); + if (Nam == "0") + views.setViewVisibility(R.id.strName, View.GONE); + if (Image == "0") + views.setViewVisibility(R.id.strImg, View.GONE); + if (Days == "0") + views.setViewVisibility(R.id.strMeres, View.GONE); + if (Prog == "0") + views.setViewVisibility(R.id.strProg, View.GONE); + + + if (act != 0) { + Intent action; + if (act == 2) { + action = new Intent(context, ChartView.class); + } else { + action = new Intent(context, Details.class); + } + action.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); + action.putExtra("id", id); + PendingIntent pendingIntent = PendingIntent.getActivity(context, id, + action, 0); + views.setOnClickPendingIntent(R.id.widg, pendingIntent); + views.setOnClickPendingIntent(R.id.strImg, pendingIntent); + } appWidgetManager.updateAppWidget(appWidgetId, views); } diff --git a/src/com/forfolias/leleDroid/StrWidgetConfig.java b/src/com/forfolias/leleDroid/StrWidgetConfig.java index b2b5fde..961bab0 100644 --- a/src/com/forfolias/leleDroid/StrWidgetConfig.java +++ b/src/com/forfolias/leleDroid/StrWidgetConfig.java @@ -3,34 +3,185 @@ import android.app.Activity; import android.appwidget.AppWidgetManager; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.view.View; import android.widget.ArrayAdapter; +import android.widget.CheckBox; import android.widget.Spinner; import android.widget.Toast; public class StrWidgetConfig extends Activity { private int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; + public Integer textColor = 0xff000000; public StrWidgetConfig() { super(); } + + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + setResult(RESULT_CANCELED); + setContentView(R.layout.widget_conf); + + setStrSpinner(); + setActionSpinner(); + + findViewById(R.id.ok).setOnClickListener(mOnClickListener); + findViewById(R.id.widgetButtonTextColor).setOnClickListener( + pickTextColor); + + Intent intent = getIntent(); + Bundle extras = intent.getExtras(); + if (extras != null) { + mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, + AppWidgetManager.INVALID_APPWIDGET_ID); + } + + if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { + finish(); + } + } + + View.OnClickListener mOnClickListener = new View.OnClickListener() { + public void onClick(View v) { + final Context context = StrWidgetConfig.this; + String Vpref = ""; + String Npref = ""; + String Ipref = ""; + String Dpref = ""; + String Ppref = ""; + Integer action = -1; + CheckBox cb; + Spinner strSpin = (Spinner) findViewById(R.id.strSpinner); + Integer id = (int) (strSpin.getSelectedItemId() + 1); + savePref(context, mAppWidgetId, id.toString(), "id_"); + + savePref(context, mAppWidgetId, textColor.toString(), "textColor_"); + + strSpin = (Spinner) findViewById(R.id.actionSpinner); + action = (int) (strSpin.getSelectedItemId()); + savePref(context, mAppWidgetId, action.toString(), "action_"); + + cb = (CheckBox) findViewById(R.id.CBVathmos); + if (cb.isChecked()) + Vpref = "1"; + else + Vpref = "0"; + savePref(context, mAppWidgetId, Vpref, "dispVathmos_"); + + cb = (CheckBox) findViewById(R.id.CBName); + if (cb.isChecked()) + Npref = "1"; + else + Npref = "0"; + savePref(context, mAppWidgetId, Npref, "dispName_"); + + cb = (CheckBox) findViewById(R.id.CBImage); + if (cb.isChecked()) + Ipref = "1"; + else + Ipref = "0"; + savePref(context, mAppWidgetId, Ipref, "dispImage_"); + + cb = (CheckBox) findViewById(R.id.CBDays); + if (cb.isChecked()) + Dpref = "1"; + else + Dpref = "0"; + savePref(context, mAppWidgetId, Dpref, "dispDays_"); + + cb = (CheckBox) findViewById(R.id.CBProg); + if (cb.isChecked()) + Ppref = "1"; + else + Ppref = "0"; + savePref(context, mAppWidgetId, Dpref, "dispProg_"); + + if (Vpref == "0" && Npref == "0" && Ipref == "0" && Dpref == "0" && Ppref == "0") { + Toast.makeText(getApplicationContext(), R.string.emptyDisplay, + Toast.LENGTH_LONG).show(); + return; + } + + AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); + StrWidget.updateAppWidget(context, appWidgetManager, mAppWidgetId, + id, action, textColor.toString(), Vpref, Npref, Ipref, Dpref, Ppref); + + Intent resultValue = new Intent(); + resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); + setResult(RESULT_OK, resultValue); + finish(); + } + }; + + View.OnClickListener pickTextColor = new View.OnClickListener() { + public void onClick(View v) { + + final ColorPickerDialog d = new ColorPickerDialog( + StrWidgetConfig.this, 0xff000000); + d.setAlphaSliderVisible(true); + + d.setButton(getResources().getString(R.string.ok), + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + textColor = d.getColor(); + findViewById(R.id.widgetButtonTextColor) + .setBackgroundColor(textColor); + } + }); + + d.setButton2(getResources().getString(R.string.cancel), + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + } + }); + d.show(); + } + }; + + static void savePref(Context context, int appWidgetId, String text, String key) { + SharedPreferences.Editor prefs = context.getSharedPreferences( + "com.forfolias.leleDroid.StrWidget", 0).edit(); + prefs.putString(key + appWidgetId, text); + prefs.commit(); + } + + static String getPref(Context context, int appWidgetId, String pref) { + SharedPreferences prefs = context.getSharedPreferences( + "com.forfolias.leleDroid.StrWidget", 0); + String prefix = prefs.getString(pref + appWidgetId, null); + if (prefix != null){ + return prefix; + }else { + return "-1"; + } + } + + void setActionSpinner(){ + Spinner actionSpin = (Spinner) findViewById(R.id.actionSpinner); + String[] actionList = { + getResources().getString(R.string.none), + getResources().getString(R.string.details), + getResources().getString(R.string.chart)}; + ArrayAdapter adapter1 = new ArrayAdapter(this, + android.R.layout.simple_spinner_item, actionList); + adapter1.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + actionSpin.setAdapter(adapter1); + } - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - setResult(RESULT_CANCELED); - setContentView(R.layout.widget_conf); - - Spinner strSpin = (Spinner) findViewById(R.id.strSpinner); - final Integer N = Str.getLengh(); - if (N == 0){ - Toast.makeText(getApplicationContext(), R.string.emptyList, Toast.LENGTH_LONG).show(); - finish(); - } + void setStrSpinner(){ + Spinner strSpin = (Spinner) findViewById(R.id.strSpinner); + final Integer N = Str.getLengh(); + if (N == 0) { + Toast.makeText(getApplicationContext(), R.string.emptyList, + Toast.LENGTH_LONG).show(); + finish(); + } String[] strList = new String[N]; for (int i = 0; i < N; i++) { strList[i] = Str.getStrFromId(i + 1).getName(); @@ -39,56 +190,5 @@ public void onCreate(Bundle icicle) { android.R.layout.simple_spinner_item, strList); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); strSpin.setAdapter(adapter); - - findViewById(R.id.ok).setOnClickListener(mOnClickListener); - - Intent intent = getIntent(); - Bundle extras = intent.getExtras(); - if (extras != null) { - mAppWidgetId = extras.getInt( - AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); - } - - if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { - finish(); - } - } - - View.OnClickListener mOnClickListener = new View.OnClickListener() { - public void onClick(View v) { - final Context context =StrWidgetConfig.this; - - Spinner strSpin = (Spinner) findViewById(R.id.strSpinner); - - Long id = strSpin.getSelectedItemId() + 1; - - saveIdPref(context, mAppWidgetId, id.toString()); - - AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); - StrWidget.updateAppWidget(context, appWidgetManager, - mAppWidgetId, id.toString()); - - Intent resultValue = new Intent(); - resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); - setResult(RESULT_OK, resultValue); - finish(); - } - }; - - static void saveIdPref(Context context, int appWidgetId, String text) { - SharedPreferences.Editor prefs = context.getSharedPreferences("com.forfolias.leleDroid.StrWidget", 0).edit(); - prefs.putString("prefix_" + appWidgetId, text); - prefs.commit(); - } - - static String getStrId(Context context, int appWidgetId) { - SharedPreferences prefs = context.getSharedPreferences( - "com.forfolias.leleDroid.StrWidget", 0); - String prefix = prefs.getString("prefix_" + appWidgetId, null); - if (prefix != null) { - return prefix; - } else { - return "0"; - } } } diff --git a/src/com/forfolias/leleDroid/drawables/AlphaPatternDrawable.java b/src/com/forfolias/leleDroid/drawables/AlphaPatternDrawable.java new file mode 100644 index 0000000..f98554d --- /dev/null +++ b/src/com/forfolias/leleDroid/drawables/AlphaPatternDrawable.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2010 Daniel Nilsson + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.forfolias.leleDroid.drawables; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.Bitmap.Config; +import android.graphics.drawable.Drawable; + +/** + * This drawable that draws a simple white and gray chessboard pattern. + * It's pattern you will often see as a background behind a + * partly transparent image in many applications. + * @author Daniel Nilsson + */ +public class AlphaPatternDrawable extends Drawable { + + private int mRectangleSize = 10; + + private Paint mPaint = new Paint(); + private Paint mPaintWhite = new Paint(); + private Paint mPaintGray = new Paint(); + + private int numRectanglesHorizontal; + private int numRectanglesVertical; + + /** + * Bitmap in which the pattern will be cahched. + */ + private Bitmap mBitmap; + + public AlphaPatternDrawable(int rectangleSize) { + mRectangleSize = rectangleSize; + mPaintWhite.setColor(0xffffffff); + mPaintGray.setColor(0xffcbcbcb); + } + + @Override + public void draw(Canvas canvas) { + canvas.drawBitmap(mBitmap, null, getBounds(), mPaint); + } + + @Override + public int getOpacity() { + return 0; + } + + @Override + public void setAlpha(int alpha) { + throw new UnsupportedOperationException("Alpha is not supported by this drawwable."); + } + + @Override + public void setColorFilter(ColorFilter cf) { + throw new UnsupportedOperationException("ColorFilter is not supported by this drawwable."); + } + + @Override + protected void onBoundsChange(Rect bounds) { + super.onBoundsChange(bounds); + + int height = bounds.height(); + int width = bounds.width(); + + numRectanglesHorizontal = (int) Math.ceil((width / mRectangleSize)); + numRectanglesVertical = (int) Math.ceil(height / mRectangleSize); + + generatePatternBitmap(); + + } + + /** + * This will generate a bitmap with the pattern + * as big as the rectangle we were allow to draw on. + * We do this to chache the bitmap so we don't need to + * recreate it each time draw() is called since it + * takes a few milliseconds. + */ + private void generatePatternBitmap(){ + + if(getBounds().width() <= 0 || getBounds().height() <= 0){ + return; + } + + mBitmap = Bitmap.createBitmap(getBounds().width(), getBounds().height(), Config.ARGB_8888); + Canvas canvas = new Canvas(mBitmap); + + Rect r = new Rect(); + boolean verticalStartWhite = true; + for (int i = 0; i <= numRectanglesVertical; i++) { + + boolean isWhite = verticalStartWhite; + for (int j = 0; j <= numRectanglesHorizontal; j++) { + + r.top = i * mRectangleSize; + r.left = j * mRectangleSize; + r.bottom = r.top + mRectangleSize; + r.right = r.left + mRectangleSize; + + canvas.drawRect(r, isWhite ? mPaintWhite : mPaintGray); + + isWhite = !isWhite; + } + + verticalStartWhite = !verticalStartWhite; + + } + + } + +} diff --git a/src/com/forfolias/leleDroid/leleDroid.java b/src/com/forfolias/leleDroid/leleDroid.java index 582113f..660b2e5 100644 --- a/src/com/forfolias/leleDroid/leleDroid.java +++ b/src/com/forfolias/leleDroid/leleDroid.java @@ -47,9 +47,10 @@ public void onItemClick(AdapterView a, View v, int i, long l) { strList.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() { public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { - menu.add(0, 1, 0, R.string.view); - menu.add(0, 2, 0, R.string.edit); - menu.add(0, 3, 0, R.string.delete); + menu.add(0, 1, 0, R.string.details); + menu.add(0, 2, 0, R.string.chart); + menu.add(0, 3, 0, R.string.edit); + menu.add(0, 4, 0, R.string.delete); } }); } @@ -61,7 +62,7 @@ public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { - /* View Str */ + /* View Str details */ case 1: Intent view = new Intent(this, com.forfolias.leleDroid.Details.class); @@ -69,9 +70,18 @@ public boolean onContextItemSelected(MenuItem item) { view.putExtras(b); startActivity(view); return true; + + /* View Str chart dialog */ + case 2: + Intent viewChart = new Intent(this, + com.forfolias.leleDroid.ChartView.class); + b.putInt("id", menuInfo.position + 1); + viewChart.putExtras(b); + startActivity(viewChart); + return true; /* Edit Str */ - case 2: + case 3: Intent edit = new Intent(this, com.forfolias.leleDroid.Properties.class); b.putInt("id", menuInfo.position + 1); @@ -80,7 +90,7 @@ public boolean onContextItemSelected(MenuItem item) { return true; /* Delete Str */ - case 3: + case 4: if (Str.deleteStrFromId(menuInfo.position + 1)) { Intent intent = getIntent(); finish(); diff --git a/src/com/forfolias/leleDroid/views/ColorPanelView.java b/src/com/forfolias/leleDroid/views/ColorPanelView.java new file mode 100644 index 0000000..8151297 --- /dev/null +++ b/src/com/forfolias/leleDroid/views/ColorPanelView.java @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2010 Daniel Nilsson + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package com.forfolias.leleDroid.views; + +import com.forfolias.leleDroid.drawables.AlphaPatternDrawable; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.View; + +/** + * This class draws a panel which which will be filled with a color which can be set. + * It can be used to show the currently selected color which you will get from + * the {@link ColorPickerView}. + * @author Daniel Nilsson + * + */ +public class ColorPanelView extends View{ + + /** + * The width in pixels of the border + * surrounding the color panel. + */ + private final static float BORDER_WIDTH_PX = 1; + + private static float mDensity = 1f; + + private int mBorderColor = 0xff6E6E6E; + private int mColor = 0xff000000; + + private Paint mBorderPaint; + private Paint mColorPaint; + + private RectF mDrawingRect; + private RectF mColorRect; + + private AlphaPatternDrawable mAlphaPattern; + + + public ColorPanelView(Context context){ + this(context, null); + } + + public ColorPanelView(Context context, AttributeSet attrs){ + this(context, attrs, 0); + } + + public ColorPanelView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + init(); + } + + private void init(){ + mBorderPaint = new Paint(); + mColorPaint = new Paint(); + mDensity = getContext().getResources().getDisplayMetrics().density; + } + + + @Override + protected void onDraw(Canvas canvas) { + + final RectF rect = mColorRect; + + if(BORDER_WIDTH_PX > 0){ + mBorderPaint.setColor(mBorderColor); + canvas.drawRect(mDrawingRect, mBorderPaint); + } + + if(mAlphaPattern != null){ + mAlphaPattern.draw(canvas); + } + + mColorPaint.setColor(mColor); + + canvas.drawRect(rect, mColorPaint); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + + int width = MeasureSpec.getSize(widthMeasureSpec); + int height = MeasureSpec.getSize(heightMeasureSpec); + + setMeasuredDimension(width, height); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + mDrawingRect = new RectF(); + mDrawingRect.left = getPaddingLeft(); + mDrawingRect.right = w - getPaddingRight(); + mDrawingRect.top = getPaddingTop(); + mDrawingRect.bottom = h - getPaddingBottom(); + + setUpColorRect(); + + } + + private void setUpColorRect(){ + final RectF dRect = mDrawingRect; + + float left = dRect.left + BORDER_WIDTH_PX; + float top = dRect.top + BORDER_WIDTH_PX; + float bottom = dRect.bottom - BORDER_WIDTH_PX; + float right = dRect.right - BORDER_WIDTH_PX; + + mColorRect = new RectF(left,top, right, bottom); + + mAlphaPattern = new AlphaPatternDrawable((int)(5 * mDensity)); + + mAlphaPattern.setBounds(Math.round(mColorRect.left), + Math.round(mColorRect.top), + Math.round(mColorRect.right), + Math.round(mColorRect.bottom)); + + } + + /** + * Set the color that should be shown by this view. + * @param color + */ + public void setColor(int color){ + mColor = color; + invalidate(); + } + + /** + * Get the color currently show by this view. + * @return + */ + public int getColor(){ + return mColor; + } + + /** + * Set the color of the border surrounding the panel. + * @param color + */ + public void setBorderColor(int color){ + mBorderColor = color; + invalidate(); + } + + /** + * Get the color of the border surrounding the panel. + */ + public int getBorderColor(){ + return mBorderColor; + } + +} diff --git a/src/com/forfolias/leleDroid/views/ColorPickerView.java b/src/com/forfolias/leleDroid/views/ColorPickerView.java new file mode 100644 index 0000000..26277c4 --- /dev/null +++ b/src/com/forfolias/leleDroid/views/ColorPickerView.java @@ -0,0 +1,959 @@ +/* + * Copyright (C) 2010 Daniel Nilsson + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package com.forfolias.leleDroid.views; + +import com.forfolias.leleDroid.drawables.AlphaPatternDrawable; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ComposeShader; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.Point; +import android.graphics.PorterDuff; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.Paint.Align; +import android.graphics.Paint.Style; +import android.graphics.Shader.TileMode; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +/** + * Displays a color picker to the user and allow them + * to select a color. A slider for the alpha channel is + * also available. Enable it by setting + * setAlphaSliderVisible(boolean) to true. + * @author Daniel Nilsson + */ +public class ColorPickerView extends View{ + + public interface OnColorChangedListener{ + public void onColorChanged(int color); + } + + private final static int PANEL_SAT_VAL = 0; + private final static int PANEL_HUE = 1; + private final static int PANEL_ALPHA = 2; + + /** + * The width in pixels of the border + * surrounding all color panels. + */ + private final static float BORDER_WIDTH_PX = 1; + + /** + * The width in dp of the hue panel. + */ + private float HUE_PANEL_WIDTH = 30f; + /** + * The height in dp of the alpha panel + */ + private float ALPHA_PANEL_HEIGHT = 20f; + /** + * The distance in dp between the different + * color panels. + */ + private float PANEL_SPACING = 10f; + /** + * The radius in dp of the color palette tracker circle. + */ + private float PALETTE_CIRCLE_TRACKER_RADIUS = 5f; + /** + * The dp which the tracker of the hue or alpha panel + * will extend outside of its bounds. + */ + private float RECTANGLE_TRACKER_OFFSET = 2f; + + + private static float mDensity = 1f; + + private OnColorChangedListener mListener; + + private Paint mSatValPaint; + private Paint mSatValTrackerPaint; + + private Paint mHuePaint; + private Paint mHueTrackerPaint; + + private Paint mAlphaPaint; + private Paint mAlphaTextPaint; + + private Paint mBorderPaint; + + private Shader mValShader; + private Shader mSatShader; + private Shader mHueShader; + private Shader mAlphaShader; + + private int mAlpha = 0xff; + private float mHue = 360f; + private float mSat = 0f; + private float mVal = 0f; + + private String mAlphaSliderText = "Alpha"; + private int mSliderTrackerColor = 0xff1c1c1c; + private int mBorderColor = 0xff6E6E6E; + private boolean mShowAlphaPanel = false; + + /* + * To remember which panel that has the "focus" when + * processing hardware button data. + */ + private int mLastTouchedPanel = PANEL_SAT_VAL; + + /** + * Offset from the edge we must have or else + * the finger tracker will get clipped when + * it is drawn outside of the view. + */ + private float mDrawingOffset; + + + /* + * Distance form the edges of the view + * of where we are allowed to draw. + */ + private RectF mDrawingRect; + + private RectF mSatValRect; + private RectF mHueRect; + private RectF mAlphaRect; + + private AlphaPatternDrawable mAlphaPattern; + + private Point mStartTouchPoint = null; + + + public ColorPickerView(Context context){ + this(context, null); + } + + public ColorPickerView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ColorPickerView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + private void init(){ + mDensity = getContext().getResources().getDisplayMetrics().density; + PALETTE_CIRCLE_TRACKER_RADIUS *= mDensity; + RECTANGLE_TRACKER_OFFSET *= mDensity; + HUE_PANEL_WIDTH *= mDensity; + ALPHA_PANEL_HEIGHT *= mDensity; + PANEL_SPACING = PANEL_SPACING * mDensity; + + mDrawingOffset = calculateRequiredOffset(); + + initPaintTools(); + + //Needed for receiving trackball motion events. + setFocusable(true); + setFocusableInTouchMode(true); + } + + private void initPaintTools(){ + + mSatValPaint = new Paint(); + mSatValTrackerPaint = new Paint(); + mHuePaint = new Paint(); + mHueTrackerPaint = new Paint(); + mAlphaPaint = new Paint(); + mAlphaTextPaint = new Paint(); + mBorderPaint = new Paint(); + + + mSatValTrackerPaint.setStyle(Style.STROKE); + mSatValTrackerPaint.setStrokeWidth(2f * mDensity); + mSatValTrackerPaint.setAntiAlias(true); + + mHueTrackerPaint.setColor(mSliderTrackerColor); + mHueTrackerPaint.setStyle(Style.STROKE); + mHueTrackerPaint.setStrokeWidth(2f * mDensity); + mHueTrackerPaint.setAntiAlias(true); + + mAlphaTextPaint.setColor(0xff1c1c1c); + mAlphaTextPaint.setTextSize(14f * mDensity); + mAlphaTextPaint.setAntiAlias(true); + mAlphaTextPaint.setTextAlign(Align.CENTER); + mAlphaTextPaint.setFakeBoldText(true); + + + } + + private float calculateRequiredOffset(){ + float offset = Math.max(PALETTE_CIRCLE_TRACKER_RADIUS, RECTANGLE_TRACKER_OFFSET); + offset = Math.max(offset, BORDER_WIDTH_PX * mDensity); + + return offset * 1.5f; + } + + private int[] buildHueColorArray(){ + + int[] hue = new int[361]; + + int count = 0; + for(int i = hue.length -1; i >= 0; i--, count++){ + hue[count] = Color.HSVToColor(new float[]{i, 1f, 1f}); + } + + return hue; + } + + + @Override + protected void onDraw(Canvas canvas) { + + if(mDrawingRect.width() <= 0 || mDrawingRect.height() <= 0) return; + + drawSatValPanel(canvas); + drawHuePanel(canvas); + drawAlphaPanel(canvas); + + } + + private void drawSatValPanel(Canvas canvas){ + + final RectF rect = mSatValRect; + + if(BORDER_WIDTH_PX > 0){ + mBorderPaint.setColor(mBorderColor); + canvas.drawRect(mDrawingRect.left, mDrawingRect.top, rect.right + BORDER_WIDTH_PX, rect.bottom + BORDER_WIDTH_PX, mBorderPaint); + } + + if (mValShader == null) { + mValShader = new LinearGradient(rect.left, rect.top, rect.left, rect.bottom, + 0xffffffff, 0xff000000, TileMode.CLAMP); + } + + int rgb = Color.HSVToColor(new float[]{mHue,1f,1f}); + + mSatShader = new LinearGradient(rect.left, rect.top, rect.right, rect.top, + 0xffffffff, rgb, TileMode.CLAMP); + ComposeShader mShader = new ComposeShader(mValShader, mSatShader, PorterDuff.Mode.MULTIPLY); + mSatValPaint.setShader(mShader); + + canvas.drawRect(rect, mSatValPaint); + + Point p = satValToPoint(mSat, mVal); + + mSatValTrackerPaint.setColor(0xff000000); + canvas.drawCircle(p.x, p.y, PALETTE_CIRCLE_TRACKER_RADIUS - 1f * mDensity, mSatValTrackerPaint); + + mSatValTrackerPaint.setColor(0xffdddddd); + canvas.drawCircle(p.x, p.y, PALETTE_CIRCLE_TRACKER_RADIUS, mSatValTrackerPaint); + + } + + private void drawHuePanel(Canvas canvas){ + + final RectF rect = mHueRect; + + if(BORDER_WIDTH_PX > 0){ + mBorderPaint.setColor(mBorderColor); + canvas.drawRect(rect.left - BORDER_WIDTH_PX, + rect.top - BORDER_WIDTH_PX, + rect.right + BORDER_WIDTH_PX, + rect.bottom + BORDER_WIDTH_PX, + mBorderPaint); + } + + if (mHueShader == null) { + mHueShader = new LinearGradient(rect.left, rect.top, rect.left, rect.bottom, buildHueColorArray(), null, TileMode.CLAMP); + mHuePaint.setShader(mHueShader); + } + + canvas.drawRect(rect, mHuePaint); + + float rectHeight = 4 * mDensity / 2; + + Point p = hueToPoint(mHue); + + RectF r = new RectF(); + r.left = rect.left - RECTANGLE_TRACKER_OFFSET; + r.right = rect.right + RECTANGLE_TRACKER_OFFSET; + r.top = p.y - rectHeight; + r.bottom = p.y + rectHeight; + + + canvas.drawRoundRect(r, 2, 2, mHueTrackerPaint); + + } + + private void drawAlphaPanel(Canvas canvas){ + + if(!mShowAlphaPanel || mAlphaRect == null || mAlphaPattern == null) return; + + final RectF rect = mAlphaRect; + + if(BORDER_WIDTH_PX > 0){ + mBorderPaint.setColor(mBorderColor); + canvas.drawRect(rect.left - BORDER_WIDTH_PX, + rect.top - BORDER_WIDTH_PX, + rect.right + BORDER_WIDTH_PX, + rect.bottom + BORDER_WIDTH_PX, + mBorderPaint); + } + + + mAlphaPattern.draw(canvas); + + float[] hsv = new float[]{mHue,mSat,mVal}; + int color = Color.HSVToColor(hsv); + int acolor = Color.HSVToColor(0, hsv); + + mAlphaShader = new LinearGradient(rect.left, rect.top, rect.right, rect.top, + color, acolor, TileMode.CLAMP); + + + mAlphaPaint.setShader(mAlphaShader); + + canvas.drawRect(rect, mAlphaPaint); + + if(mAlphaSliderText != null && mAlphaSliderText!= ""){ + canvas.drawText(mAlphaSliderText, rect.centerX(), rect.centerY() + 4 * mDensity, mAlphaTextPaint); + } + + float rectWidth = 4 * mDensity / 2; + + Point p = alphaToPoint(mAlpha); + + RectF r = new RectF(); + r.left = p.x - rectWidth; + r.right = p.x + rectWidth; + r.top = rect.top - RECTANGLE_TRACKER_OFFSET; + r.bottom = rect.bottom + RECTANGLE_TRACKER_OFFSET; + + canvas.drawRoundRect(r, 2, 2, mHueTrackerPaint); + + } + + + private Point hueToPoint(float hue){ + + final RectF rect = mHueRect; + final float height = rect.height(); + + Point p = new Point(); + + p.y = (int) (height - (hue * height / 360f) + rect.top); + p.x = (int) rect.left; + + return p; + } + + private Point satValToPoint(float sat, float val){ + + final RectF rect = mSatValRect; + final float height = rect.height(); + final float width = rect.width(); + + Point p = new Point(); + + p.x = (int) (sat * width + rect.left); + p.y = (int) ((1f - val) * height + rect.top); + + return p; + } + + private Point alphaToPoint(int alpha){ + + final RectF rect = mAlphaRect; + final float width = rect.width(); + + Point p = new Point(); + + p.x = (int) (width - (alpha * width / 0xff) + rect.left); + p.y = (int) rect.top; + + return p; + + } + + private float[] pointToSatVal(float x, float y){ + + final RectF rect = mSatValRect; + float[] result = new float[2]; + + float width = rect.width(); + float height = rect.height(); + + if (x < rect.left){ + x = 0f; + } + else if(x > rect.right){ + x = width; + } + else{ + x = x - rect.left; + } + + if (y < rect.top){ + y = 0f; + } + else if(y > rect.bottom){ + y = height; + } + else{ + y = y - rect.top; + } + + + result[0] = 1.f / width * x; + result[1] = 1.f - (1.f / height * y); + + return result; + } + + private float pointToHue(float y){ + + final RectF rect = mHueRect; + + float height = rect.height(); + + if (y < rect.top){ + y = 0f; + } + else if(y > rect.bottom){ + y = height; + } + else{ + y = y - rect.top; + } + + return 360f - (y * 360f / height); + } + + private int pointToAlpha(int x){ + + final RectF rect = mAlphaRect; + final int width = (int) rect.width(); + + if(x < rect.left){ + x = 0; + } + else if(x > rect.right){ + x = width; + } + else{ + x = x - (int)rect.left; + } + + return 0xff - (x * 0xff / width); + + } + + + @Override + public boolean onTrackballEvent(MotionEvent event) { + + float x = event.getX(); + float y = event.getY(); + + boolean update = false; + + + if(event.getAction() == MotionEvent.ACTION_MOVE){ + + switch(mLastTouchedPanel){ + + case PANEL_SAT_VAL: + + float sat, val; + + sat = mSat + x/50f; + val = mVal - y/50f; + + if(sat < 0f){ + sat = 0f; + } + else if(sat > 1f){ + sat = 1f; + } + + if(val < 0f){ + val = 0f; + } + else if(val > 1f){ + val = 1f; + } + + mSat = sat; + mVal = val; + + update = true; + + break; + + case PANEL_HUE: + + float hue = mHue - y * 10f; + + if(hue < 0f){ + hue = 0f; + } + else if(hue > 360f){ + hue = 360f; + } + + mHue = hue; + + update = true; + + break; + + case PANEL_ALPHA: + + if(!mShowAlphaPanel || mAlphaRect == null){ + update = false; + } + else{ + + int alpha = (int) (mAlpha - x*10); + + if(alpha < 0){ + alpha = 0; + } + else if(alpha > 0xff){ + alpha = 0xff; + } + + mAlpha = alpha; + + + update = true; + } + + break; + } + + + } + + + if(update){ + + if(mListener != null){ + mListener.onColorChanged(Color.HSVToColor(mAlpha, new float[]{mHue, mSat, mVal})); + } + + invalidate(); + return true; + } + + + return super.onTrackballEvent(event); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + + boolean update = false; + + switch(event.getAction()){ + + case MotionEvent.ACTION_DOWN: + + mStartTouchPoint = new Point((int)event.getX(), (int)event.getY()); + + update = moveTrackersIfNeeded(event); + + break; + + case MotionEvent.ACTION_MOVE: + + update = moveTrackersIfNeeded(event); + + break; + + case MotionEvent.ACTION_UP: + + mStartTouchPoint = null; + + update = moveTrackersIfNeeded(event); + + break; + + } + + if(update){ + + if(mListener != null){ + mListener.onColorChanged(Color.HSVToColor(mAlpha, new float[]{mHue, mSat, mVal})); + } + + invalidate(); + return true; + } + + + return super.onTouchEvent(event); + } + + private boolean moveTrackersIfNeeded(MotionEvent event){ + + if(mStartTouchPoint == null) return false; + + boolean update = false; + + int startX = mStartTouchPoint.x; + int startY = mStartTouchPoint.y; + + + if(mHueRect.contains(startX, startY)){ + mLastTouchedPanel = PANEL_HUE; + + mHue = pointToHue(event.getY()); + + update = true; + } + else if(mSatValRect.contains(startX, startY)){ + + mLastTouchedPanel = PANEL_SAT_VAL; + + float[] result = pointToSatVal(event.getX(), event.getY()); + + mSat = result[0]; + mVal = result[1]; + + update = true; + } + else if(mAlphaRect != null && mAlphaRect.contains(startX, startY)){ + + mLastTouchedPanel = PANEL_ALPHA; + + mAlpha = pointToAlpha((int)event.getX()); + + update = true; + } + + + return update; + } + + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + + int width = 0; + int height = 0; + + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + + int widthAllowed = MeasureSpec.getSize(widthMeasureSpec); + int heightAllowed = MeasureSpec.getSize(heightMeasureSpec); + + + widthAllowed = chooseWidth(widthMode, widthAllowed); + heightAllowed = chooseHeight(heightMode, heightAllowed); + + + if(!mShowAlphaPanel){ + height = (int) (widthAllowed - PANEL_SPACING - HUE_PANEL_WIDTH); + + //If calculated height (based on the width) is more than the allowed height. + if(height > heightAllowed){ + height = heightAllowed; + width = (int) (height + PANEL_SPACING + HUE_PANEL_WIDTH); + } + else{ + width = widthAllowed; + } + } + else{ + + width = (int) (heightAllowed - ALPHA_PANEL_HEIGHT + HUE_PANEL_WIDTH); + + if(width > widthAllowed){ + width = widthAllowed; + height = (int) (widthAllowed - HUE_PANEL_WIDTH + ALPHA_PANEL_HEIGHT); + } + else{ + height = heightAllowed; + } + + + } + + + setMeasuredDimension(width, height); + } + + private int chooseWidth(int mode, int size){ + if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.EXACTLY) { + return size; + } else { // (mode == MeasureSpec.UNSPECIFIED) + return getPrefferedWidth(); + } + } + + private int chooseHeight(int mode, int size){ + if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.EXACTLY) { + return size; + } else { // (mode == MeasureSpec.UNSPECIFIED) + return getPrefferedHeight(); + } + } + + private int getPrefferedWidth(){ + + int width = getPrefferedHeight(); + + if(mShowAlphaPanel){ + width -= (PANEL_SPACING + ALPHA_PANEL_HEIGHT); + } + + + return (int) (width + HUE_PANEL_WIDTH + PANEL_SPACING); + + } + + private int getPrefferedHeight(){ + + int height = (int)(200 * mDensity); + + if(mShowAlphaPanel){ + height += PANEL_SPACING + ALPHA_PANEL_HEIGHT; + } + + return height; + } + + + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + mDrawingRect = new RectF(); + mDrawingRect.left = mDrawingOffset + getPaddingLeft(); + mDrawingRect.right = w - mDrawingOffset - getPaddingRight(); + mDrawingRect.top = mDrawingOffset + getPaddingTop(); + mDrawingRect.bottom = h - mDrawingOffset - getPaddingBottom(); + + setUpSatValRect(); + setUpHueRect(); + setUpAlphaRect(); + } + + private void setUpSatValRect(){ + + final RectF dRect = mDrawingRect; + float panelSide = dRect.height() - BORDER_WIDTH_PX * 2; + + if(mShowAlphaPanel){ + panelSide -= PANEL_SPACING + ALPHA_PANEL_HEIGHT; + } + + float left = dRect.left + BORDER_WIDTH_PX; + float top = dRect.top + BORDER_WIDTH_PX; + float bottom = top + panelSide; + float right = left + panelSide; + + mSatValRect = new RectF(left,top, right, bottom); + } + + private void setUpHueRect(){ + final RectF dRect = mDrawingRect; + + float left = dRect.right - HUE_PANEL_WIDTH + BORDER_WIDTH_PX; + float top = dRect.top + BORDER_WIDTH_PX; + float bottom = dRect.bottom - BORDER_WIDTH_PX - (mShowAlphaPanel ? (PANEL_SPACING + ALPHA_PANEL_HEIGHT) : 0); + float right = dRect.right - BORDER_WIDTH_PX; + + mHueRect = new RectF(left, top, right, bottom); + } + + private void setUpAlphaRect(){ + + if(!mShowAlphaPanel) return; + + final RectF dRect = mDrawingRect; + + float left = dRect.left + BORDER_WIDTH_PX; + float top = dRect.bottom - ALPHA_PANEL_HEIGHT + BORDER_WIDTH_PX; + float bottom = dRect.bottom - BORDER_WIDTH_PX; + float right = dRect.right - BORDER_WIDTH_PX; + + mAlphaRect = new RectF(left, top, right, bottom); + + + mAlphaPattern = new AlphaPatternDrawable((int) (5 * mDensity)); + mAlphaPattern.setBounds(Math.round(mAlphaRect.left), Math + .round(mAlphaRect.top), Math.round(mAlphaRect.right), Math + .round(mAlphaRect.bottom)); + + + + } + + + /** + * Set a OnColorChangedListener to get notified when the color + * selected by the user has changed. + * @param listener + */ + public void setOnColorChangedListener(OnColorChangedListener listener){ + mListener = listener; + } + + /** + * Set the color of the border surrounding all panels. + * @param color + */ + public void setBorderColor(int color){ + mBorderColor = color; + invalidate(); + } + + /** + * Get the color of the border surrounding all panels. + */ + public int getBorderColor(){ + return mBorderColor; + } + + /** + * Get the current color this view is showing. + * @return the current color. + */ + public int getColor(){ + return Color.HSVToColor(mAlpha, new float[]{mHue,mSat,mVal}); + } + + /** + * Set the color the view should show. + * @param color The color that should be selected. + */ + public void setColor(int color){ + setColor(color, false); + } + + /** + * Set the color this view should show. + * @param color The color that should be selected. + * @param callback If you want to get a callback to + * your OnColorChangedListener. + */ + public void setColor(int color, boolean callback){ + + int alpha = Color.alpha(color); + int red = Color.red(color); + int blue = Color.blue(color); + int green = Color.green(color); + + float[] hsv = new float[3]; + + Color.RGBToHSV(red, green, blue, hsv); + + mAlpha = alpha; + mHue = hsv[0]; + mSat = hsv[1]; + mVal = hsv[2]; + + if(callback && mListener != null){ + mListener.onColorChanged(Color.HSVToColor(mAlpha, new float[]{mHue, mSat, mVal})); + } + + invalidate(); + } + + /** + * Get the drawing offset of the color picker view. + * The drawing offset is the distance from the side of + * a panel to the side of the view minus the padding. + * Useful if you want to have your own panel below showing + * the currently selected color and want to align it perfectly. + * @return The offset in pixels. + */ + public float getDrawingOffset(){ + return mDrawingOffset; + } + + /** + * Set if the user is allowed to adjust the alpha panel. Default is false. + * If it is set to false no alpha will be set. + * @param visible + */ + public void setAlphaSliderVisible(boolean visible){ + + if(mShowAlphaPanel != visible){ + mShowAlphaPanel = visible; + + /* + * Reset all shader to force a recreation. + * Otherwise they will not look right after + * the size of the view has changed. + */ + mValShader = null; + mSatShader = null; + mHueShader = null; + mAlphaShader = null;; + + requestLayout(); + } + + } + + public void setSliderTrackerColor(int color){ + mSliderTrackerColor = color; + + mHueTrackerPaint.setColor(mSliderTrackerColor); + + invalidate(); + } + + public int getSliderTrackerColor(){ + return mSliderTrackerColor; + } + + /** + * Set the text that should be shown in the + * alpha slider. Set to null to disable text. + * @param res string resource id. + */ + public void setAlphaSliderText(int res){ + String text = getContext().getString(res); + setAlphaSliderText(text); + } + + /** + * Set the text that should be shown in the + * alpha slider. Set to null to disable text. + * @param text Text that should be shown. + */ + public void setAlphaSliderText(String text){ + mAlphaSliderText = text; + invalidate(); + } + + /** + * Get the current value of the text + * that will be shown in the alpha + * slider. + * @return + */ + public String getAlphaSliderText(){ + return mAlphaSliderText; + } +}