diff --git a/core/res/drawable-default/seekbar_progress.xml b/core/res/drawable-default/seekbar_progress.xml
new file mode 100644
index 0000000..5a3f503
--- /dev/null
+++ b/core/res/drawable-default/seekbar_progress.xml
@@ -0,0 +1,27 @@
+
+
+ -
+
+
-
+
+
-
+
+
+
+
+ -
+
+
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/res/drawable-default/seekbar_thumb.xml b/core/res/drawable-default/seekbar_thumb.xml
new file mode 100644
index 0000000..33febfd
--- /dev/null
+++ b/core/res/drawable-default/seekbar_thumb.xml
@@ -0,0 +1,27 @@
+
+
+ -
+
+
-
+
+
-
+
+
+
+
+ -
+
+
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/res/drawable-default/seekbar_track.xml b/core/res/drawable-default/seekbar_track.xml
new file mode 100644
index 0000000..9398961
--- /dev/null
+++ b/core/res/drawable-default/seekbar_track.xml
@@ -0,0 +1,9 @@
+
+
+ -
+
+
+
\ No newline at end of file
diff --git a/core/res/ex-layout/main.xml b/core/res/ex-layout/main.xml
index f5e77d2..655dfd0 100644
--- a/core/res/ex-layout/main.xml
+++ b/core/res/ex-layout/main.xml
@@ -26,9 +26,12 @@
width="match_parent"
height="wrap_content"
margin="5dp"/>
-
diff --git a/core/res/style/defaults.xml b/core/res/style/defaults.xml
index 6acfc9c..8d9e24c 100644
--- a/core/res/style/defaults.xml
+++ b/core/res/style/defaults.xml
@@ -21,6 +21,12 @@
- @drawable/scrollbar_thumb
+
+
diff --git a/core/src/br/nullexcept/mux/graphics/drawable/LayerListDrawable.java b/core/src/br/nullexcept/mux/graphics/drawable/LayerListDrawable.java
index 8be7b94..91e7d59 100644
--- a/core/src/br/nullexcept/mux/graphics/drawable/LayerListDrawable.java
+++ b/core/src/br/nullexcept/mux/graphics/drawable/LayerListDrawable.java
@@ -36,7 +36,7 @@ public void draw(Canvas canvas) {
public int getWidth() {
int width = 1;
for (Layer layer: layers) {
- width = Math.max(width, layer.drawable.getWidth()+layer.padding.left+layer.padding.right);
+ width = Math.max(width, layer.getWidth()+layer.padding.left+layer.padding.right);
}
return width;
}
@@ -45,7 +45,7 @@ public int getWidth() {
public int getHeight() {
int height = 1;
for (Layer layer: layers) {
- height = Math.max(height, layer.drawable.getWidth()+layer.padding.bottom+layer.padding.top);
+ height = Math.max(height, layer.getHeight()+layer.padding.bottom+layer.padding.top);
}
return height;
}
@@ -105,5 +105,13 @@ public void setBounds(Rect rect) {
drawable.setBounds(tmp);
}
+
+ public int getWidth() {
+ return size.width == -1 ? drawable.getWidth() : size.width;
+ }
+
+ public int getHeight() {
+ return size.height == -1 ? drawable.getHeight() : size.height;
+ }
}
}
diff --git a/core/src/br/nullexcept/mux/graphics/drawable/SelectorDrawable.java b/core/src/br/nullexcept/mux/graphics/drawable/SelectorDrawable.java
index e00951f..5d67434 100644
--- a/core/src/br/nullexcept/mux/graphics/drawable/SelectorDrawable.java
+++ b/core/src/br/nullexcept/mux/graphics/drawable/SelectorDrawable.java
@@ -51,6 +51,16 @@ public boolean setState(StateList state) {
return !current.equals(old);
}
+ @Override
+ public int getWidth() {
+ return current == null ? super.getWidth() : current.getWidth();
+ }
+
+ @Override
+ public int getHeight() {
+ return current == null ? super.getHeight() : current.getHeight();
+ }
+
private class StateDrawable {
public final StateList stateList;
public final Drawable drawable;
diff --git a/core/src/br/nullexcept/mux/lang/Function3.java b/core/src/br/nullexcept/mux/lang/Function3.java
new file mode 100644
index 0000000..8597c05
--- /dev/null
+++ b/core/src/br/nullexcept/mux/lang/Function3.java
@@ -0,0 +1,5 @@
+package br.nullexcept.mux.lang;
+
+public interface Function3 {
+ void run(A a, B b, C c);
+}
diff --git a/core/src/br/nullexcept/mux/res/LayoutInflater.java b/core/src/br/nullexcept/mux/res/LayoutInflater.java
index b2d1082..8323977 100644
--- a/core/src/br/nullexcept/mux/res/LayoutInflater.java
+++ b/core/src/br/nullexcept/mux/res/LayoutInflater.java
@@ -108,6 +108,7 @@ private ViewGroup.LayoutParams parseLayoutParams(AttributeList attr){
registerView("TextView", TextView::new);
registerView("Switch", Switch::new);
registerView("View", View::new);
+ registerView("SeekBar", SeekBar::new);
}
public static void registerView(String name, ViewRegister register){
diff --git a/core/src/br/nullexcept/mux/res/Parser.java b/core/src/br/nullexcept/mux/res/Parser.java
index c6c5ceb..2469424 100644
--- a/core/src/br/nullexcept/mux/res/Parser.java
+++ b/core/src/br/nullexcept/mux/res/Parser.java
@@ -227,6 +227,7 @@ private static Bitmap openBitmap(String path) {
}
public static Drawable parseDrawable(Resources resources, String value) {
+ value = value.trim();
if (value.startsWith("#")){
return new ColorDrawable(Color.parseColor(value));
} else {
@@ -242,7 +243,7 @@ public static Drawable parseDrawable(Resources resources, String value) {
}
}
}
- Log.error(LOG_TAG,"Invalid background value: "+value);
+ Log.error(LOG_TAG,"Invalid drawable source value: "+value);
return null;
}
diff --git a/core/src/br/nullexcept/mux/view/AttrList.java b/core/src/br/nullexcept/mux/view/AttrList.java
index 2295645..cc9bb68 100644
--- a/core/src/br/nullexcept/mux/view/AttrList.java
+++ b/core/src/br/nullexcept/mux/view/AttrList.java
@@ -45,4 +45,9 @@ public class AttrList {
public static final String summary = "summary";
public static final String icon = "icon";
public static final String visibility = "visibility";
+ public static final String progress = "progress";
+ public static final String max = "max";
+ public static final String thumbDrawable = "thumbDrawable";
+ public static final String trackDrawable = "trackDrawable";
+ public static final String progressDrawable = "progressDrawable";
}
diff --git a/core/src/br/nullexcept/mux/widget/FlowLayout.java b/core/src/br/nullexcept/mux/widget/FlowLayout.java
index 12de964..78c867e 100644
--- a/core/src/br/nullexcept/mux/widget/FlowLayout.java
+++ b/core/src/br/nullexcept/mux/widget/FlowLayout.java
@@ -3,6 +3,7 @@
import br.nullexcept.mux.app.Context;
import br.nullexcept.mux.graphics.Point;
import br.nullexcept.mux.res.AttributeList;
+import br.nullexcept.mux.view.AttrList;
import br.nullexcept.mux.view.Gravity;
import br.nullexcept.mux.view.View;
import br.nullexcept.mux.view.ViewGroup;
@@ -10,11 +11,13 @@
public class FlowLayout extends ViewGroup {
private int dividerSize = 16;
public FlowLayout(Context context) {
- super(context);
+ this(context, null);
}
- public FlowLayout(Context context, AttributeList attrs) {
- super(context, attrs);
+ public FlowLayout(Context context, AttributeList init) {
+ super(context, init);
+ AttributeList attrs = initialAttributes();
+ attrs.searchDimension(AttrList.dividerSize, x -> dividerSize = x.intValue());
}
@Override
diff --git a/core/src/br/nullexcept/mux/widget/SeekBar.java b/core/src/br/nullexcept/mux/widget/SeekBar.java
new file mode 100644
index 0000000..124e210
--- /dev/null
+++ b/core/src/br/nullexcept/mux/widget/SeekBar.java
@@ -0,0 +1,211 @@
+package br.nullexcept.mux.widget;
+
+import br.nullexcept.mux.app.Context;
+import br.nullexcept.mux.graphics.*;
+import br.nullexcept.mux.graphics.drawable.ColorDrawable;
+import br.nullexcept.mux.input.KeyEvent;
+import br.nullexcept.mux.input.MotionEvent;
+import br.nullexcept.mux.input.MouseEvent;
+import br.nullexcept.mux.lang.Function3;
+import br.nullexcept.mux.res.AttributeList;
+import br.nullexcept.mux.view.AttrList;
+import br.nullexcept.mux.view.View;
+
+public class SeekBar extends View {
+ private int progress;
+ private int max;
+
+ private Drawable trackDrawable = new ColorDrawable(Color.RED);
+ private Drawable thumbDrawable = new ColorDrawable(Color.GREEN);
+ private Drawable progressDrawable = new ColorDrawable(Color.BLUE);
+ private final Rect rect = new Rect();
+ private Function3 seekListener;
+ protected boolean captureScrollPosition = false;
+ protected int scrollY = 0;
+
+ public SeekBar(Context context) {
+ this(context, null);
+ }
+
+ public SeekBar(Context context, AttributeList attrs) {
+ super(context, attrs);
+ AttributeList init = initialAttributes();
+ init.searchFloat(AttrList.max, x -> setMax(x.intValue()));
+ init.searchFloat(AttrList.progress, x -> setProgress(x.intValue()));
+ init.searchDrawable(AttrList.progressDrawable, this::setProgressDrawable);
+ init.searchDrawable(AttrList.thumbDrawable, this::setThumbDrawable);
+ init.searchDrawable(AttrList.trackDrawable, this::setTrackDrawable);
+
+ setFocusable(true);
+ }
+
+ private void seek(int value, boolean user) {
+ value = Math.min(max, Math.max(0, value));
+ if (value != progress) {
+ this.progress = value;
+ invalidate();
+ if (seekListener != null) {
+ seekListener.run(this, user, value);
+ }
+ }
+ }
+
+ // (View, FromUser, Value)
+ public void setOnSeekListener(Function3 listener) {
+ seekListener = listener;
+ }
+
+ @Override
+ protected void onKeyEvent(KeyEvent keyEvent) {
+ int percent = (int) (max * 0.02);
+ switch (keyEvent.getKeyCode()) {
+ case KeyEvent.KEY_UP:
+ case KeyEvent.KEY_RIGHT:
+ seek(progress+percent, true);
+ break;
+ case KeyEvent.KEY_LEFT:
+ case KeyEvent.KEY_DOWN:
+ seek(progress-percent, true);
+ break;
+ default:
+ System.err.println("DEF");
+ super.onKeyEvent(keyEvent);
+ break;
+ }
+ }
+
+ @Override
+ protected boolean dispatchMouseEvent(MouseEvent event) {
+ if (isFocused()) {
+ if (!captureScrollPosition) {
+ captureScrollPosition = true;
+ scrollY = event.getScroll().y;
+ return super.dispatchMouseEvent(event);
+ } else {
+ int y = event.getScroll().y - scrollY;
+ scrollY = event.getScroll().y;
+ if (y != 0) {
+ int percent = (int) (max * 0.02);
+ seek(progress+(percent * (y < 0 ? -1 : 1)), true);
+ }
+ }
+ }
+ return super.dispatchMouseEvent(event);
+ }
+
+ @Override
+ public void onFocusChanged(boolean focused) {
+ super.onFocusChanged(focused);
+ captureScrollPosition = false;
+ }
+
+ @Override
+ protected boolean onMouseEvent(MouseEvent mouseEvent) {
+ float x = mouseEvent.getX();
+ int w = (int) ((x/(double)getMeasuredWidth()) * max);
+ seek(w, true);
+ requestFocus();
+ return mouseEvent.getAction() == MotionEvent.ACTION_DOWN;
+ }
+
+ public void setMax(int max) {
+ this.max = Math.max(1, max);
+ setProgress(progress);
+ invalidate();
+ }
+
+ public void setProgress(int progress) {
+ seek(progress, false);
+ }
+
+ public void setTrackDrawable(Drawable trackDrawable) {
+ this.trackDrawable = trackDrawable;
+ changeDrawableState();
+ measure();
+ invalidate();
+ }
+
+ public void setThumbDrawable(Drawable thumbDrawable) {
+ this.thumbDrawable = thumbDrawable;
+ changeDrawableState();
+ measure();
+ invalidate();
+ }
+
+ public void setProgressDrawable(Drawable progressDrawable) {
+ this.progressDrawable = progressDrawable;
+ changeDrawableState();
+ measure();
+ invalidate();
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ int thumbOffset = 0;
+ int height = getMeasuredHeight();
+ int width = getMeasuredWidth();
+ if (thumbDrawable != null) {
+ thumbOffset = thumbDrawable.getWidth() / 2;
+ }
+ if (trackDrawable != null) {
+ rect.setPosition(thumbOffset, (height-trackDrawable.getHeight())/2);
+ rect.setSize(Math.max(1, width-(thumbOffset*2)), trackDrawable.getHeight());
+ trackDrawable.setBounds(rect);
+ trackDrawable.draw(canvas);
+ }
+ if (progressDrawable != null) {
+ rect.setPosition(thumbOffset, (height-progressDrawable.getHeight())/2);
+ int w = (width-(thumbOffset*2));
+ w = (int) Math.round(w * ((double)progress/max));
+ rect.setSize(Math.max(1, w), progressDrawable.getHeight());
+ progressDrawable.setBounds(rect);
+ progressDrawable.draw(canvas);
+ }
+ if (thumbDrawable != null) {
+ int x = (int) (Math.max(1, width-(thumbOffset*2)) * ((double)progress/max));
+ int y = (height - thumbDrawable.getHeight()) / 2;
+ rect.setPosition(x, y);
+ rect.setSize(thumbDrawable.getWidth(), thumbDrawable.getHeight());
+ thumbDrawable.setBounds(rect);
+ thumbDrawable.draw(canvas);
+ }
+ }
+
+ @Override
+ protected Size onMeasureContent(int parentWidth, int parentHeight) {
+ Size def = super.onMeasureContent(parentWidth, parentHeight);
+ int mh = 0;
+ if (thumbDrawable != null) {
+ mh = Math.max(thumbDrawable.getHeight(), mh);
+ }
+ if (trackDrawable != null) {
+ mh = Math.max(trackDrawable.getHeight(), mh);
+ }
+ if (progressDrawable != null) {
+ mh = Math.max(progressDrawable.getHeight(), mh);
+ }
+ def.height += mh * 2;
+ return def;
+ }
+
+ @Override
+ protected void changeDrawableState() {
+ if (thumbDrawable != null) {
+ if (thumbDrawable.setState(getStateList())) {
+ invalidate();
+ }
+ }
+ if (trackDrawable != null) {
+ if (trackDrawable.setState(getStateList())) {
+ invalidate();
+ }
+ }
+ if (progressDrawable != null) {
+ if (progressDrawable.setState(getStateList())) {
+ invalidate();
+ }
+ }
+ super.changeDrawableState();
+ }
+}